ZOJ 2110 Tempter of the Bone
题目描述:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2110
这是在ZOJ上做的第一道题,题目倒不是很难,悲剧的是剪枝太多,我悲剧了两个晚上,今天终于做出来了,很高兴!贴一下我的代码,顺便奉上《图论算法理论应用与实践》上的解析代码供大家参考;
我的代码:
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int x,y,M,N,T,dx,dy; bool ans,flag[10][10]; char ch[10][10]; int r[4]= {0,-1,0,1},c[4]= {1,0,-1,0}; bool charge(int x,int y) { if(x<0||y<0||x>=M||y>=N||flag[x][y]||ch[x][y]=='X') return false; return true; } void solve(int x,int y,int depth) { if(ch[x][y]=='D'&&depth==T) { ans=true; return ; } int temp = (T-depth) - fabs(x-dx) - fabs(y-dy); if( temp<0 || temp%2 ) return; //剪的第二枝; if(ch[x][y]!='D') { flag[x][y]=1; for(int i=0; i<4; i++) { if(charge(x+r[i],y+c[i])) { solve(x+r[i],y+c[i],depth+1); if(ans) return; //剪的第三枝,这里是一个关键的地方,我就是因为这个没有写TLE了好多次; } } flag[x][y]=0; } return; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d%d%d",&M,&N,&T)&&(M||N||T)) { getchar(); memset(flag,0,sizeof(flag)); int wall=0; for(int i=0; i<M; i++) { for(int j=0; j<N; j++) { scanf( "%c", &ch[i][j]); if(ch[i][j]=='S') { x=i,y=j; } if(ch[i][j]=='X') wall++; if(ch[i][j]=='D') { dx=i,dy=j; } } getchar(); } if(N*M-wall<=T) //剪的第一枝,这个是必然的; { printf("NO\n"); continue; } ans=false; solve(x,y,0); if(ans) printf("YES\n"); else printf("NO\n"); } return 0; }
《图论算法理论应用与实践》上的解析代码:
#include <cstdio> #include <cmath> //用到了求绝对值的函数fabs char map[9][9]; //迷宫地图 int n, m, t; //迷宫的大小,及迷宫的门会在第t秒开启 int di, dj; //(di,dj):门的位置 bool escape; //是否成功逃脱的标志,escape为1表示能成功逃脱 int dir[4][2] = { {0,-1}, {0,1}, {1,0}, {-1,0} }; //分别表示下、上、左、右四个方向 //已经到达(si,sj)位置,且已经花费cnt秒 void dfs( int si, int sj, int cnt ) { int i, temp; if( si>n || sj>m || si<=0 || sj<=0 ) return; //边界 if( si==di && sj==dj && cnt==t ) //成功逃脱 { escape = 1; return; } //abs(x-ex) + abs(y - ey)表示现在所在的格子到目标格子的距离(不能走对角线) //t-cnt是实际还需要的步数,将他们做差 //如果temp < 0或者temp为奇数,那就不可能到达! temp = (t-cnt) - fabs(si-di) - fabs(sj-dj); if( temp<0 || temp%2 ) return; //搜索过程当中的剪枝 for( i=0; i<4; i++ ) { if( map[ si+dir[i][0] ][ sj+dir[i][1] ] != 'X') { //前进方向!将当前方格设置为墙壁‘X’ map[ si+dir[i][0] ][ sj+dir[i][1] ] = 'X'; dfs(si+dir[i][0], sj+dir[i][1], cnt+1); //从下一个位置继续搜索 if(escape) return; map[ si+dir[i][0] ][ sj+dir[i][1] ] = '.'; //后退方向!恢复现场! } } return; } int main( ) { int i, j; //循环变量 int si, sj; //小狗的起始位置 freopen("in.txt","r",stdin); while( scanf("%d%d%d", &n, &m, &t) ) { if( n==0 && m==0 && t==0 ) break; //测试数据结束 int wall = 0; char temp; scanf( "%c", &temp ); //见下面的备注 for( i=1; i<=n; i++ ) { for( j=1; j<=m; j++ ) { scanf( "%c", &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++; } scanf( "%c", &temp ); } if( n*m-wall <= t ) //搜索前的剪枝 { printf( "NO\n" ); continue; } escape = 0; map[si][sj] = 'X'; dfs( si, sj, 0 ); if( escape ) printf( "YES\n" ); //成功逃脱 else printf( "NO\n" ); } return 0; }