搜索DFS+BFS和剪枝问题
2015-08-02 17:53
459 查看
HUD 1010
题意:输入一个n*m的迷宫,和一个T:可以在迷宫中生存的最大时间。S为起点,D为终点。并且,每个格子只能踩一次,且只能维持一秒,然后该块地板就会塌陷。所以你必须每秒走一步,且到D点时,所用时间为T。用深搜。
之前,误以为就是找到最短路,结果不是,而是恰好T秒走出迷宫。用DFS,超时可见剪枝的重要。
这题的剪枝主要是两个方面。
1:利用曼哈顿距离剪枝 —– 算出终点到该点的距离,与剩余的时间进行比较,如果到终点的距离大于剩余的时间,很明显是不能到达的。
2:利用奇偶剪枝 —- 如果二者之间距离与剩余时间的差是奇数,那么就舍掉,因为当二者的差值是0时可以刚好到达,当二者的差值大于0时,就必须绕个远路拐两个直角到达,而此时必须是偶数。
HDU 1175
题意就是我们平时玩连连看的意思,然后只能转两个弯,不能从外围走。
然后用DFS很残酷的TLE了。后来才想到一个剪枝点。
剪枝处:用vis的二维数组来存储当前的转弯数的情况,当前(i,j)这个点的转弯数大于vis[i][j]的时候,我们就return,因为vis
存储的是全局的最优解,这真是个大大的剪枝处。将标记数组的功能用的淋漓尽致,以后要记着点。
ps:剪枝来源:/article/1439542.html;
未完待续 :)
题意:输入一个n*m的迷宫,和一个T:可以在迷宫中生存的最大时间。S为起点,D为终点。并且,每个格子只能踩一次,且只能维持一秒,然后该块地板就会塌陷。所以你必须每秒走一步,且到D点时,所用时间为T。用深搜。
之前,误以为就是找到最短路,结果不是,而是恰好T秒走出迷宫。用DFS,超时可见剪枝的重要。
这题的剪枝主要是两个方面。
1:利用曼哈顿距离剪枝 —– 算出终点到该点的距离,与剩余的时间进行比较,如果到终点的距离大于剩余的时间,很明显是不能到达的。
2:利用奇偶剪枝 —- 如果二者之间距离与剩余时间的差是奇数,那么就舍掉,因为当二者的差值是0时可以刚好到达,当二者的差值大于0时,就必须绕个远路拐两个直角到达,而此时必须是偶数。
[code]#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <math.h> using namespace std; int n,m,T; const int N = 10; char Map ; bool vis ; bool ans; int dir[4][2]={0,1,1,0,0,-1,-1,0}; int edx,edy; void DFS(int x,int y,int t) { if(x==edx && y==edy && t==T) {ans=true;return;} if(t>=T) return; if(x==edx && y==edy) return; int dis=T-(fabs(edx-x)+fabs(edy-y)+t);//剪枝处 if(dis<0 ||dis%2 ) return; for(int i=0;i<4;i++) { int xx=x+dir[i][0]; int yy=y+dir[i][1]; if(xx<1||xx>n) continue; if(yy<1||yy>m) continue; if(Map[xx][yy]=='X' ||!vis[xx][yy]) continue; vis[xx][yy]=false; DFS(xx,yy,t+1); if(ans) return; vis[xx][yy]=true; } return; } int main() { while((scanf("%d %d %d",&n,&m,&T))!=EOF) { if(n==0 &&m==0 && T==0) break; int x,y; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf(" %c",&Map[i][j]); if(Map[i][j]=='S') x=i,y=j; if(Map[i][j]=='D') edx=i,edy=j; } ans=false; memset(vis,true,sizeof(vis)); vis[x][y]=false; DFS(x,y,0); if(ans) printf("YES\n"); else printf("NO\n"); } return 0; }
HDU 1175
题意就是我们平时玩连连看的意思,然后只能转两个弯,不能从外围走。
然后用DFS很残酷的TLE了。后来才想到一个剪枝点。
剪枝处:用vis的二维数组来存储当前的转弯数的情况,当前(i,j)这个点的转弯数大于vis[i][j]的时候,我们就return,因为vis
存储的是全局的最优解,这真是个大大的剪枝处。将标记数组的功能用的淋漓尽致,以后要记着点。
ps:剪枝来源:/article/1439542.html;
[code]#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1000+10; int Map ; int vis ; int n,m,edx,edy; bool flag; int dir[4][2]={0,1,1,0,0,-1,-1,0}; void dfs(int x,int y,int cnt,int aim) { if(flag) return; if(x<1||y<1||x>n||y>m||cnt>2) return; if(x==edx && y==edy && cnt<=2) {flag=true;return;} if(Map[x][y]!=0) return; if(vis[x][y]!=-1&&vis[x][y]<=cnt) return;//剪枝处 vis[x][y]=cnt; for(int i=0;i<4;i++) { int xx=x+dir[i][0]; int yy=y+dir[i][1]; if(i==aim) dfs(xx,yy,cnt,i); else dfs(xx,yy,cnt+1,i); } } int main() { //freopen("test.txt","r",stdin); //freopen("out.txt","w",stdout); while(~scanf("%d %d",&n,&m)) { if(n==0 &&m==0) break; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&Map[i][j]); int Q; scanf("%d",&Q); while(Q--) { int x,y; flag=false; scanf("%d %d %d %d",&x,&y,&edx,&edy); if(x<1||x>n||y<1||y>m||edx<1||edx>n||edy<1||edy>m||(x==edx&&y==edy)) {printf("NO\n");continue;} if(Map[x][y]!=Map[edx][edy]||Map[x][y]==0 ||Map[edx][edy]==0) {printf("NO\n");continue;} memset(vis,-1,sizeof(vis)); vis[x][y]=0; for(int i=0;i<4;i++) { int xx=x+dir[i][0]; int yy=y+dir[i][1]; dfs(xx,yy,0,i); if(flag) break; } if(flag) printf("YES\n"); else printf("NO\n"); } } return 0; }
未完待续 :)
相关文章推荐
- hdoj5336
- AXIS-web.xml里配置axis报错addChild: Child name 'AxisServlet' is not unique 解决办法
- stopcoroutine 不起作用
- 游戏引擎选择、Mac下和Windows下UnrealEngine 4体验对比
- 喵呜的虚拟城市(最短路)
- 【算法导论第五章】课后习题解析
- HDU 1016 Prime Ring Problem
- MSSQL数据库导入导出大全二(SQL语句)
- LAMP结合NFS完成小型博客站点建设
- 因为权限原因要在filter里使用spring- service所产生的问题
- LeetCode-- Construct Binary Tree from Preorder and Inorder Traversal
- typename typelink typeurl 和各种link
- /*用C#求一个数,它的九倍是它的反序数*/
- ssh无密码登陆
- 最长回文子序列的java解法
- svn如何提交.so文件
- Length of Last Word
- HDU 1878.欧拉回路【欧拉路及欧拉回路初接触】【8月2】
- Visual Assist X的用法
- Linux内核和驱动编译常见问题