首页 > 其他分享 >[刷题笔记] Luogu P3073 [USACO13FEB]Tractor S

[刷题笔记] Luogu P3073 [USACO13FEB]Tractor S

时间:2023-06-07 21:13:49浏览次数:60  
标签:二分 bfs P3073 return int Luogu USACO13FEB bool include

Problem

Solution

汽车拉力比赛差不多,思路都是二分,二分\(d\),但是汽车拉力比赛从一个路标开始搜即可,本题没有给定起点。一条合法路径起点是未知的,不得随便从一个点开始搜,否则可能找不到正确路径。

怎么处理呢?
容易想到对于每一个二分的\(d\),开一个\(n^2\)的循环,从每一个点开始搜,如果从这个点搜满足,则return true。

暴力代码如下:

点击查看代码
bool check1(int d)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            memset(vis,INF,sizeof(vis));//每一次搜前清空
            if(check(i,j,d)) return true; //以i,j作为起点搜
        }
    }
    return false;
}

这样处理复杂度是很高的,一定会炸:
image

如何优化呢?

上述做法对于每一次二分的\(d\)都进行\(n^2\)暴力,我们发现,每一次\(n^2\)暴力\(d\)是唯一的,bfs都是在当前节点上尽可能的扩散。我们可以对每一个走过的点记录,如果这次bfs不行则下次bfs一定不能再走这个点,类似于记忆化搜索,可以理解为不能重蹈覆辙,因为如果走上了这个标记的点就一定不可行。(相当于把原来错误的道路又走了一遍,浪费时间)

如果文字很抽象,我们可以画图举例:
image

假设红色代表一次bfs,显然没有走过一半的点,那么下一次bfs就一定不能再走上红点,不然又进了死胡同,一定不行。

这样,我们不光剩下了每次搜索前的memset,还不用每个\((i,j)\)都作为起点搜(如果\((i,j)\)标记了显然不能作为起点)

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cmath>
#define N 550
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> PAIR;
int n;
int mapp[N][N];
int vis[N][N];
double goal = 0;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
bool flg;
int minn = INF,maxn = -1;
bool check(int i,int j,int d)
{
    double cnt=1;
    queue <PAIR> q;
    q.push(PAIR(i,j));
    vis[i][j] = 1;
    while(!q.empty())
    {
        PAIR p=q.front();
        q.pop();
        if(cnt >= goal) 
        {
            return true;
        }
        for(int i=0;i<4;i++)
        {
            int ax = p.first + dx[i];
            int ay = p.second + dy[i];
            if(ax>=1&&ax<=n&&ay>=1&&ay<=n&&vis[ax][ay] == INF && abs(mapp[ax][ay]-mapp[p.first][p.second]) <= d)
            {
                cnt++;
                q.push(PAIR(ax,ay));
                vis[ax][ay] = vis[p.first][p.second]+1;
            }
        }
    }
    if(cnt >= goal) return true;
    else return false;
}
bool check1(int d)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(vis[i][j]==INF)
            {
                if(check(i,j,d)) return true;
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d",&n);
    goal = round(n*n*1.0/2); //四舍五入
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++) scanf("%d",&mapp[i][j]),maxn = max(maxn,mapp[i][j]),minn = min(minn,mapp[i][j]);
    }
    int l = 1,r = INF;
    while(l <= r)
    {
        memset(vis,INF,sizeof(vis));
        int mid = (l+r)/2;
        if(check1(mid)) r = mid-1;
        else l = mid+1;
    }
    cout<<l<<endl;
    return 0;
}

标签:二分,bfs,P3073,return,int,Luogu,USACO13FEB,bool,include
From: https://www.cnblogs.com/SXqwq/p/17464569.html

相关文章

  • Luogu P3605 [USACO17JAN]Promotion Counting P
    [USACO17JAN]PromotionCountingP题目描述Thecowshaveonceagaintriedtoformastartupcompany,failingtorememberfrompastexperiencethatcowsmaketerriblemanagers!Thecows,convenientlynumbered\(1\ldotsN\)(\(1\leqN\leq100,000\)),o......
  • Luogu P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
    [Vani有约会]雨天的尾巴/【模板】线段树合并题目背景深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。无奈......
  • LuoguP4318 完全平方数
    标签:莫比乌斯函数,容斥完全平方数题目描述小X自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。这天是小X的生日,小W想送一个数给他作为生日礼物。当然他......
  • Luogu P2709 小B的询问
    https://www.luogu.com.cn/problem/P2709#submit小B的询问题目描述小B有一个长为\(n\)的整数序列\(a\),值域为\([1,k]\)。他一共有\(m\)个询问,每个询问给定一个区间\([l,r]\),求:\[\sum\limits_{i=1}^kc_i^2\]其中\(c_i\)表示数字\(i\)在\([l,r]\)中的出现次数......
  • [刷题笔记] Luogu P2895 Meteor Shower S
    ProblemSolution显然bfs,只不过有了限定条件,有实时的流星雨这里提供两种做法:Solution1这也是我一开始的做法模拟实时流星,由于bfs是按层搜的,是严格按照时间递增搜的,故可以模拟实时放流星。需要注意放流星的时间,如果第\(t\)秒有流星,则该秒不可以走,需要在每一秒前放流星。那......
  • [刷题笔记] LuoguP2658 汽车拉力比赛
    ProblemSolution需要找到最小满足题意的\(d\),显然\(d\)满足单调性,考虑二分二分\(d\),然后直接bfs,每次bfs判断能不能走的时候还需要加上高度差不超过二分的\(d\)(即满足),bfs跑完后看看所有的路标都被访问了没。(可以记录个数,因为不可能重复走)二分的时候注意\(l\)从0开始,不然会WA......
  • luogu P8497 [NOI2022] 移除石子
    题面传送门不好评价?首先我们考虑最基础的情况,当\(k=0,l_i=r_i\)时,相当于我们需要判定一个状态能不能被消完。这相当于我们要执行若干次\(2\)操作,使得每个位置要么大于等于\(2\),要么为\(0\)。为此我们需要挖掘一些操作\(2\)的性质。性质\(1\):操作区间长度不会超过\(5......
  • Luogu P1007 独木桥
    题目描述link思路找到独木桥的中间位置,最少时间考虑在端点左侧的,向左走,在端点右侧的向右走.最多时间考虑在端点左侧的向右走,在端点右侧的向左走.最少时间即为最优情况下最多的时间,最多时间即为最差情况下的最多时间Code#include<cstdio>#include<algorithm>......
  • Luogu P1008 三连击
    题目描述link思路因为\(1-9\)且不能重复使用,所以从\(123\)循环至\(789\),相应的\(2\)倍,\(3\)倍,即为另两个数字.对每个数字进行拆分,所用数字使用次数\(+1\),判断是否每个数字都被使用且只使用一次,输出即可.Code#include<cstdio>#include<cstring>i......
  • 最小生成树_LuoguP1669
    P1669P1669[USACO04DEC]BadCowtractorsS题目传送门题意简化:在一个有\(N\)个点\(M\)条边的图中选出\(N-1\)条边构成一棵树,使得树的总边权最大,求最大总边权。上述问题即为最小(大)生成树问题,本题为最大生成树,如有未详者可以移步P3366。该问题一般是Kruskal和Prim......