HDOJ 1010 Tempter of the Bone

来源:互联网 发布:微信h5牛牛房卡版源码 编辑:程序博客网 时间:2024/05/16 11:29

题意:

   n*m的矩阵,S是出发点,D是终点,

    .是可以走的,X是不可以走的,T秒的时候D

    才会被打开,否则就出不去,输出doggie

    后能否出去。

分析:奇偶剪枝

    这个题目用一般的搜索无法完成,因为题目

    要求在指定的时间内完成,所以只好一步一

    步来啦,用DFS解决

    但是如果直接用dfs结果会超时,网上说是用

    一种奇偶剪枝的方法来间断搜索时间,

    下面是剪枝的简单理论:

map看作

       0 1 0 1 0 1

       1 0 1 0 1 0

       0 1 0 1 0 1

       1 0 1 0 1 0

       0 1 0 1 0 1

0->1 需要奇数步

0->0 需要偶数步

那么设所在位置 (x,y) 与目标位置 (dx,dy)

如果abs(x-y)+abs(dx-dy)为偶数,则说明 abs(x-y) abs(dx-dy)的奇偶性相同,需要走偶数步

如果abs(x-y)+abs(dx-dy)为奇数,那么说明 abs(x-y) abs(dx-dy)的奇偶性不同,需要走奇数步

理解为 abs(si-sj)+abs(di-dj)的奇偶性就确定了所需要的步数的奇偶性!!

(ti-setp)表示剩下还需要走的步数,由于题目要求要在 ti时恰好到达,

那么  (ti-step) abs(x-y)+abs(dx-dy) 的奇偶性必须相同

因此 temp=ti-step-abs(dx-x)-abs(dy-y)必然为偶数!

 

   一般这种dfs题目都需要一个map[][]记录个点的值,

   一个record[][]记录一下某点是否走过(防止走重!!)

   一个用于检测是否越界的函数isin()

   其余的就是dfs函数的设计了。

//不知道我的代码哪里错了。。。就是wa了#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int maxn=10;int n,m,t,cnt,sx,sy,gx,gy;int dx[4]= {-1,0,0,1},dy[4]= {0,1,-1,0};char mp[maxn][maxn];int visit[maxn][maxn];bool dfs(int x,int y,int cnt){    int i,j,nx,ny;    if(cnt==t&&mp[x][y]=='D')        return true;    if(x<1||x>n|y<1||y>m)        return false;    if(cnt>=t)        return false;    if(t-cnt<(abs(x-gx)+abs(y-gy)))        return false;    if((t-cnt-(int)(abs(x-gx)+abs(y-gy)))%2!=0)        return false;    //visit[x][y]=1;    for(i=0; i<4; i++)    {        nx=x+dx[i];        ny=y+dy[i];        if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!visit[nx][ny]&&mp[nx][ny]!='X')        {            visit[nx][ny]=1;            if(dfs(nx,ny,cnt+1))//看看如果走这条路是否能走出去(true)                return true;            else                visit[nx][ny]=0;//不能走出去的话就尝试下一种方式,就算是没走过这条路,故visit要标记成0,以免影响下一次的访问        }    }    return false;}int main(){    freopen("in.txt","r",stdin);    while((scanf("%d%d%d",&n,&m,&t)!=EOF)&&(n||m||t))    {        memset(visit,0,sizeof(visit));        int i,j;        for(i=1; i<=n; i++)        {            getchar();            for(j=1; j<=m; j++)            {                scanf("%c",&mp[i][j]);                if(mp[i][j]=='S')                {                    sx=i;                    sy=j;                }                if(mp[i][j]=='D')                {                    gx=i;                    gy=j;                }            }        }        visit[sx][sy]=1;        if(dfs(sx,sy,0))            printf("YES\n");        else            printf("NO\n");    }    return 0;}


 

//AC代码:这是参考了别人的代码后来改过的。。。orz#include<iostream>#include<cmath>#include<cstring>#include<queue>#include <cstdio>int fangxiang[4][2]={{-1,0},{1,0},{0,-1},{0,1}};const int MAX=101;char map[MAX][MAX];int mark[MAX][MAX];int  n,m,t;int start_x,start_y;int end_x,end_y;using namespace std;bool DFS(int x,int y,int step){int i,a,b;if(map[x][y]=='D'&&step==t)return true;if(x<1||x>n|y<1||y>m)return false;if(step>=t)//剪枝1:当step>=T时还没有找到D点return false;if(t-step<(abs(x-end_x)+abs(y-end_y)))//剪枝2:还需要的步数比理论上的最短距离还小return false;if((t-step-(int)(abs(x-end_x)+abs(y-end_y)))%2!=0) //剪枝3:比理论上的最短距离多出来的必是偶数return false;for(i=0;i<4;i++){a=x+fangxiang[i][0];b=y+fangxiang[i][1];if(a<=n&&a>=1&&b>=1&&b<=m&&map[a][b]!='X'&&!mark[a][b]) //判断三个条件:1.检验_x,_y是否越界。2.看vis[][]是否访问过。3.看map[][]是否是墙{mark[a][b]=1;if(DFS(a,b,step+1))return true;elsemark[a][b]=0;}}return false;}int main(){    //freopen("in.txt","r",stdin);int i,j;while(cin>>n>>m>>t&&(n||m||t)){memset(mark,0,sizeof(mark));for(i=1;i<=n;i++){for(j=1;j<=m;j++){ cin>>map[i][j]; if(map[i][j]=='S') { start_x=i; start_y=j; } if(map[i][j]=='D') { end_x=i;end_y=j; }}}mark[start_x][start_y]=1;if(DFS(start_x,start_y,0))cout<<"YES"<<endl;elsecout<<"NO"<<endl;}return 0;}


 

0 0
原创粉丝点击