Codeforces Round #442 (Div. 2)-广搜&剪枝&技巧&好题-D. Olya and Energy Drinks

来源:互联网 发布:英雄皮肤淘宝店 编辑:程序博客网 时间:2024/05/17 22:51

http://codeforces.com/contest/877/problem/D
给定一个点,问你从x点到y点,需要的最少时间。
没秒可以走小于等于k步。
暴力的bfs也是没谁了。。怎么可能过。
后来又写了一种方案,枚举每个点往前后左右的最大可移动距离,还是t
(再51nod见过一道类似这种方法的。)
百度之,好多方法。
① 剪枝,相同方向剪,维护局部最小距离剪。
② 把vis变量分为四个方向,然后根据方向剪。
(即对于某一个点。如果相同方向再次使来,肯定不是最短距离了,这个剪枝也不错。)
③ 并查集,并查集大佬qwq
我郁闷了,bfs本来就能在最短的达到,我还维护,根本不用维护,一旦到达那么久肯定是最优解的了qwq

#include <bits/stdc++.h>using namespace std;/*这个代码有个细节,我交了几十遍才发现,那就是,当有另一个方向到达的该点,和曾经该点的最小时间一样大, 那么不要剪掉。。也就是,那个 vis[x][y]<u.tim+1 ,不能取等号。。。坑死了*/const int maxn=1e3+320;int m,n,k;char a[maxn][maxn];struct Node{   int x,y,tim;   Node(){};   Node(int _x,int _y,int _tim){       x=_x;       y=_y;       tim=_tim;   };};queue<Node>q;int x1,y_1,x2,y2;int vis[maxn][maxn];int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};int main(){   while(~scanf("%d%d%d",&m,&n,&k)){          for(int i=1;i<=m;i++){              for(int j=1;j<=n;j++){                  scanf(" %c",&a[i][j]);                  }          }          memset(vis,0x3f,sizeof(vis));          scanf("%d%d%d%d",&x1,&y_1,&x2,&y2);          vis[x1][y_1]=0;          q.push(Node(x1,y_1,0));          int ans=1e9;           while(!q.empty()){                Node u=q.front();                         q.pop();                    for(int j=0;j<4;j++)                    {  for(int i=1;i<=k;i++){                        int xx=fx[j][1]*i+u.x;                      int yy=fx[j][0]*i+u.y;                      if(xx==x2&&yy==y2){                        vis[xx][yy]=min(vis[xx][yy],u.tim+1);                        continue;                      }                         if(xx<1||xx>m||yy<1||yy>n)break;                      if(vis[xx][yy]<u.tim+1) break;                      if(a[xx][yy]=='#') break;                          if(vis[xx][yy]>u.tim+1){                        vis[xx][yy]=u.tim+1;                        q.push(Node(xx,yy,u.tim+1));                        }                    }                    }          }          ans=vis[x2][y2];          if(ans==0x3f3f3f3f) ans=-1;          printf("%d\n",ans);    }    return 0;}

B 用方向进行剪枝。

#include <cstdio>  #include <queue>  #include <cstring>  #include <algorithm>  using namespace std;  #define mst(a,b) memset((a),(b),sizeof(a))  #define rush() int T;scanf("%d",&T);while(T--)  typedef long long ll;  const int maxn = 1005;  const ll mod = 1e9+7;  const int INF = 0x3f3f3f3f;  const double eps = 1e-9;  const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};  int n,m,k;  int sx,sy,ex,ey;  int vis[maxn][maxn];  char mp[maxn][maxn];  int dis[maxn][maxn];  struct node  {      int x,y;  }now,nex;  bool inbound(node a)  {      return a.x>=1&&a.x<=n&&a.y>=1&&a.y<=m;  }  void bfs()  {      queue<node>q;      now.x=sx;      now.y=sy;      q.push(now);      vis[sx][sy]=(1<<4)-1;           //起点只经过一次就好      while(q.size())      {          now=q.front();          q.pop();          if(now.x==ex&&now.y==ey) return;  //搜到终点          for(int i=0;i<4;i++)              //枚举方向          for(int j=1;j<=k;j++)             //枚举走的步数          {              nex.x=now.x+dir[i][0]*j;              nex.y=now.y+dir[i][1]*j;              if(!inbound(nex)||mp[nex.x][nex.y]=='#') break;    //该位置不合法              if(vis[nex.x][nex.y]&(1<<i)) break;                //从这个方向已经走过该位置              int flag=0;              if(!vis[nex.x][nex.y]) flag=1;                     //搜到没有走过的点              vis[nex.x][nex.y]|=(1<<i);                         //更新状态              if(flag)              {                  dis[nex.x][nex.y]=dis[now.x][now.y]+1;                  q.push(nex);              }          }      }  }  int main()  {      scanf("%d%d%d",&n,&m,&k);      for(int i=1;i<=n;i++)      {          scanf("%s",mp[i]+1);      }      scanf("%d%d%d%d",&sx,&sy,&ex,&ey);      bfs();      if(vis[ex][ey]) printf("%d\n",dis[ex][ey]);      else   puts("-1");      return 0;  }  
阅读全文
0 0
原创粉丝点击