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;
}

 

 

posted on 2011-09-22 19:30  _Clarence  阅读(149)  评论(0编辑  收藏  举报

导航