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;
}
浙公网安备 33010602011771号