博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu 1010 深搜+剪枝
阅读量:5102 次
发布时间:2019-06-13

本文共 5960 字,大约阅读时间需要 19 分钟。

深度搜索

剪枝

还不是很理解

贴上众神代码

//http://blog.csdn.net/vsooda/article/details/7884772 #include
#include
using namespace std;char map[10][10];int N,M,T;int di,dj,escape;int dir[4][2]={
{0,-1},{0,1},{1,0},{-1,0}};void dfs(int x,int y,int cnt){ if(x>N || y>M || x<1 || y<1 ) return; if(cnt==T && x==di && y==dj) escape=1; if(escape==1) return; int temp = (T-cnt) - abs(x-di) - abs(y-dj); if(temp<0 || temp &1) //判断奇偶,剪枝 return; for(int i=0;i<4;i++) //四个方向,堵住回去的路 { if(map[x+dir[i][0]][y+dir[i][1]]!='X') { map[x + dir[i][0]][y + dir[i][1]]='X'; dfs(x + dir[i][0], y + dir[i][1], cnt+1); map[x+dir[i][0]][y+dir[i][1]]='.'; //恢复回去 } } return;}int main(){ while(cin>>N>>M>>T, N) { int wall=0; int si,sj; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { cin>>map[i][j]; if(map[i][j]=='S') { si=i; sj=j; } else if(map[i][j]=='D') { di=i; dj=j; } else if(map[i][j]=='X') wall++; } if(T>=M*N-wall) { cout<<"NO"<

 

http://acm.hdu.edu.cn/forum/read.php?tid=6158

1 1010 temp of the bone   2   3 sample input:  4 4 4 5  5 S.X.  6 ..X.  7 ..XD  8 ....  9  10 问题: 11 (1): 12 在发现当前节点无法到达时,这点弹出栈,并且把这点的标记重新刷为'.' 13  14 (2): 15 如何在dfs中既要保证到达又要使时间正好呢?? 在函数中通过这种形式实现: 16  17 dfs(int si,int sj,int cnt) 就是用cnt来记录当时的时间,并且在 18  19 if( si==di && sj==dj && cnt==t ) 20     { 21         escape = 1; 22         return; 23     } 24  25 的时候 即当前点到达了终点并且时间恰好等于题目所给限制时间时,跳出 26 并且escape标记为真 27  28 (3): 29 如何让一个点有顺序地遍历它四周地能到达的点呢?? 30 聪明并且简短的方法是设施一个dir[4][2] 数组 控制方向 31 并且设置它的值为dir[4][2]={
{
0,-1},{
0,1},{
1,0},{-1,0}}; 32 33 遍历的时候用for(i:0->4)就非常方便了 34 35 (4): 36 千万要注意的是节点越界的情况, dfs(int si,int sj,int cnt)的时候一定要把 si, sj 控制在给你的矩阵内 在后面会提到一个我的列子 就是因为访问了[0, -1]的位置导致了其 37 38 他数据被更改 39 40 (5): 41 读入矩阵的时候,可以采用for(i = 1; i <= N; i++) 42 for(j = 1; j <= M; j++) 43 scanf("%c", &map[i][j]); 44 45 的方法,好处在于可以控制和计算每一个读入的数据,坏处是调试的时候对矩阵的观察不太方便,而且好像还会有错误,在2102"A计划"用这种方法读入数据时好像就会wa, 46 47 另一种方法是for(i = 0; i < N; i++) gets(map[i]); 48 这样读入的数据在调试观察的时候十分方便 gets()读入的默认为字符串,在vc调试的时候是显式的 可以直接观察矩阵 缺点是对矩阵中各个数据的计算和控制无法实现,需要读完后再遍历一遍 49 50 (6) 51 能用bfs还是尽量用bfs 我不会bfs.... dfs的递归在调试的时候不是很方便,而且bfs要比dfs快,调试也要方便,因为它没有递归 52 53 (7) 54 关于剪枝,没有剪枝的搜索不太可能,这题老刘上课的时候讲过两个剪枝,一个是奇偶剪枝,一个是路径剪枝 55 56 奇偶剪枝: 57 把矩阵标记成如下形式: 58 0,1,0,1,0 59 1,0,1,0,1 60 0,1,0,1,0 61 1,0,1,0,1 62 很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步 63 在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断(Si+Sj) 和 (Di+Dj) 的奇偶性就可以了 64 65 路径剪枝: 66 矩阵的大小是N*M 墙的数量记为wall 如果能走的路的数量 N*M - wall 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了 67 68 课件里面给过这题的标程,在dfs的过程中有个没提到的剪枝,就是记录当前点到终点的最短路,如果小于剩余的时间的话,就跳出 69 这个剪枝我觉得更科学,它毕竟是动态的么,标程里面是这么写的: 70 temp = (t-cnt) - abs(si-di) - abs(sj-dj); 71 if( temp<0 || temp&1 ) return; 72 73 其中求当前点到终点的最短路是这样 abs(si-di) - abs(sj-dj) 这个就比较粗糙了 明显没有考虑到碰到墙要拐弯的情况 74 那求最短路有没有什么好办法呢? 75 76 我曾经想到过用 Dijkstraq求最短路的 ,明显大才小用,在论坛里看到一个方法觉得可以用在这里 77 给定下例: 78 79 S.X. 80 ..X. 81 ..XD 82 .... 83 84 每个点到终点的最短路是不是这样呢: 85 86 S6X2 87 65X1 88 54XD 89 4321 90 91 这怎么求呢??从终点开始遍历整个数组,终点是0,它周围的点都+1,墙就不计数,依次类推,就能求得这个矩阵的一个最短时间矩阵,在dfs的时候比较当前点到终点的最短路,如果大于剩余时间的话就跳出 92 93 这个方法的预处理还是非常快的,我没有用过,但是感觉会非常有用处. 94 95 (8) 96 在做这题的时候,我碰到过一个神奇的事情,在程序运行至下面代码时 97 98 if( map[ si+dir[i][0] ][ sj+dir[i][1] ] != 'X') 99 map[ si+dir[i][0] ][ sj+dir[i][1] ] = 'X';100 101 T被改变了!! 这丝毫和T没有关系啊,怎么改变T的值呢??102 103 原来在起点map[0][0]进入时,我没有注意到map[ si+dir[i][0] ][ sj+dir[i][1] ] 实际做的是map[0][-1] = 'X'; 很危险的一个赋值,书本上千万次强调的东西让我碰上了,这个地方我找了很久,因此我觉得有必要单独列出来提醒自己104 105 //106 下面我把一个带注释的标程贴一下,不是我写的注释107 108 109 //zju 2110 Tempter of the Bone110 #include
111 #include
112 #include
113 #include
114 115 using namespace std;116 117 //迷宫地图118 //X: 墙壁,小狗不能进入119 //S: 小狗所处的位置120 //D: 迷宫的门121 //. : 空的方格122 char map[9][9];123 int n,m,t,di,dj; //(di,dj):门的位置124 bool escape;125 int dir[4][2]={
{
0,-1},{
0,1},{
1,0},{-1,0}}; //分别表示下、上、左、右四个方向126 127 void dfs(int si,int sj,int cnt) //表示起始位置为(si,sj),要求在第cnt秒达到门的位置128 {129 int i,temp;130 if( si>n || sj>m || si<=0 || sj<=0 ) return;131 132 if( si==di && sj==dj && cnt==t )133 {134 escape = 1;135 return;136 }137 138 //abs(x-ex) + abs(y - ey)表示现在所在的格子到目标格子的距离(不能走对角线)139 //t-cnt是实际还需要的步数,将他们做差140 //如果temp < 0或者temp为奇数,那就不可能到达!141 temp = (t-cnt) - abs(si-di) - abs(sj-dj);142 143 if( temp<0 || temp&1 ) return; 144 145 for( i=0; i<4; i++ )146 {147 if( map[ si+dir[i][0] ][ sj+dir[i][1] ] != 'X')148 {149 map[ si+dir[i][0] ][ sj+dir[i][1] ] = 'X';150 151 dfs(si+dir[i][0], sj+dir[i][1], cnt+1);152 153 if(escape) return;154 155 map[ si+dir[i][0] ][ sj+dir[i][1] ] = '.';156 }157 }158 159 return;160 }161 162 int main()163 {164 int i,j,si,sj;165 166 while( cin >> n >> m >> t)167 {168 if( n==0 && m==0 && t==0 )169 break;170 171 int wall = 0;172 for( i=1; i<=n; i++ )173 for( j=1; j<=m; j++ )174 { 175 cin >> map[i][j];176 if(map[i][j]=='S') { si=i; sj=j; } 177 else if( map[i][j]=='D' ) { di=i; dj=j; }178 else if( map[i][j]=='X' ) wall++;179 }180 181 if( n*m-wall <= t )182 {183 cout << "NO" << endl;184 continue;185 }186 187 escape = 0;188 map[si][sj] = 'X';189 190 dfs( si, sj, 0 );191 192 if( escape ) cout << "YES" << endl; 193 else cout << "NO" << endl; 194 }195 196 return 0;197 }198 199 这个注释当初还是帮了我很大忙的,起码让我看懂了课件

 

转载于:https://www.cnblogs.com/zhaokuo/p/4653901.html

你可能感兴趣的文章
计算机组成与功能
查看>>
JavaScript:说看懂了就懂了闭包,看懂了,还是不懂...
查看>>
L1-043. 阅览室
查看>>
HDU--1061
查看>>
SQL查询语句 group by后, 字符串合并
查看>>
CSS学习笔记 -- Position(定位)
查看>>
CSUFT 1002 Robot Navigation
查看>>
BootStrap Table和Mybatis Plus实现服务端分页
查看>>
杨氏矩阵的一些性质
查看>>
由表单重复提交引发的幂等性思考
查看>>
Git 常用命令 和 安装
查看>>
http之url和uri
查看>>
python常用模块②
查看>>
Idea 设置根目录
查看>>
深度优先搜索算法
查看>>
写第一个驱动之前
查看>>
hysbz 2243 染色(树链剖分)
查看>>
JavaScript提高:006:ASP.NET使用easyUI TABS标签updatepanel
查看>>
Clojure实现的简单短网址服务(Compojure、Ring、Korma库演示样例)
查看>>
FindWindowEx使用方法
查看>>