HDU1010 Tempter of the Bone
广搜每走
思路:简单的深搜,如果map[nextx][nexty]!='X',则以该最后点为当前节点继续搜,若继续搜没有路可走,则释放当前节点(即原来标记过,恢复为未标记,以便再以其他节点搜索时经过该点),回到上一节点,return.由于step是局部变量,其生命周期随着当前层的DFS()函数结束而结束,所以返回上一层时,step的值就是上一层的值,而不是下一层改变后的值,而visit数组因为是全局变量,因此其生命周期只有main函数结束后才结束,因此下一层对visit数组值的改变,在DFS()返回上一层时有影响,值不在是上一层的了,而是改变后的值。
刚开时不明白,逐句调试后才对深搜有了新的认识。
下面的代码,WA了好几次,就是因为把
visit[sx][sy]=1;
if(N*M-wall<=T) {printf("NO\n");continue;}
DFS(sx,sy,0);
写成
if(N*M-wall<=T) {flag=0;}
else{
DFS(sx,sy,0);visit[sx][sy]=1;}
会超时,现在也不知到为什么,可能是杭电OJ有问题吧;
刚开始使用的广搜,最后别人说不能用广搜,最后才知道原因:
下面是广搜代码:
如测试实例:
S.X.
.XD.
...X
...X
T=4;
可能路径是:'S'->(2,1)->(3,1)->(4,1)->(4,2)->(4,3)->(3,3)->'D'一共7七步,
还可能的路径是'S'->(2,1)->(3,1)->(3,2)->(3,3)->'D' 共4步;
如果先通过第一种到达了'D',由于(3,3)已被标记走过,所以会找不到符合条件的路径,不像深搜那样找不到,释放路径,可以返回去重找。
广搜每走
思路:简单的深搜,如果map[nextx][nexty]!='X',则以该最后点为当前节点继续搜,若继续搜没有路可走,则释放当前节点(即原来标记过,恢复为未标记,以便再以其他节点搜索时经过该点),回到上一节点,return.由于step是局部变量,其生命周期随着当前层的DFS()函数结束而结束,所以返回上一层时,step的值就是上一层的值,而不是下一层改变后的值,而visit数组因为是全局变量,因此其生命周期只有main函数结束后才结束,因此下一层对visit数组值的改变,在DFS()返回上一层时有影响,值不在是上一层的了,而是改变后的值。
刚开时不明白,逐句调试后才对深搜有了新的认识。
下面的代码,WA了好几次,就是因为把
visit[sx][sy]=1;
if(N*M-wall<=T) {printf("NO\n");continue;}
DFS(sx,sy,0);
写成
if(N*M-wall<=T) {flag=0;}
else{
DFS(sx,sy,0);visit[sx][sy]=1;}
会超时,现在也不知到为什么,可能是杭电OJ有问题吧;
#include<stdio.h>
#include<string.h>
#include<math.h>
int visit[10][10];
int dir[4][2]={-1,0,1,0,0,1,0,-1};
char map[10][10];
int T,N,M;
int flag;
int dx,dy;
void DFS(int sx,int sy,int step)
{
int i,nextx,nexty;
//下面两行是每次调用DFS(),进入下一层节点时,对其进行检查;
if(map[sx][sy]=='D'&&step==T) {flag=1;return;} //如果已经搜到‘D',并满足条件就返回上一层节点
if((map[sx][sy]=='D'&&step<T)||step>T)return; //如果。。。。。。,但是不满足条件则也返回上一层(由上一层的位置搜索其他路径);
for(i=0;i<4;i++)
{
nextx=sx+dir[i][0];
nexty=sy+dir[i][1];
//如果当前节点,某个方向上的下一个节点不越界,并且没有走过
if(nextx<=M&&nextx>=1&&nexty<=N&&nexty>=1&&visit[nextx][nexty]==0)
{
//如果该方向上的节点可以走,标记该节点,并搜索该节点的下一个方向上的节点;
if(map[nextx][nexty]!='X')
{visit[nextx][nexty]=1;
DFS(nextx,nexty,step+1);
if(flag) return; //下一层返回该层时,如果已找到满足条件的路径,则不用再搜该节点其他方向上的节点路径,直接返回该节点的上一层(优化时间);
visit[nextx][nexty]=0;//释放已搜索过当前节点的下一层节点;
}
}
}
}
int main()
{
int i,j,wall,sx,sy;
while(scanf("%d%d%d",&M,&N,&T),(N+M+T)!=0)
{
memset(visit,0,sizeof(visit));
flag=0;wall=0;
getchar();
for(i=1;i<=M;i++)
{
for(j=1;j<=N;j++)
{
scanf("%c",&map[i][j]);
if(map[i][j]=='S')
{
sx=i;sy=j;
}
if(map[i][j]=='X')
wall++;
}
getchar();
}
visit[sx][sy]=1;
if(N*M-wall<=T) {printf("NO\n");continue;}//如果能走的点小于T步,则直接输出(优化时间效率);取等号的原因:如果T=6,最多能走的有6个点,其最多能走5步;
DFS(sx,sy,0);
if(flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}
刚开始使用的广搜,最后别人说不能用广搜,最后才知道原因:
下面是广搜代码:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
char map[10][10];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int visit[10][10];
int n;
int m;
int T;
struct node
{
int x;
int y;
int step;
};
int BFS(int sx,int sy)
{
queue<node>Q;
node cur,next;
int i,flag=0,sum;
cur.x=sx;cur.y=sy;
visit[cur.x][cur.y]=1;
cur.step =0;
Q.push(cur);
while(!Q.empty ())
{
cur=Q.front();
Q.pop ();
for(i=0;i<4;i++)
{
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
next.step=cur.step+1;
sum=next.step;
if(next.x>=1&&next.x<=n&&next.y>=1&&next.y<=m&&visit[next.x][next.y]==0)
{
if(map[next.x][next.y]=='.')
{
Q.push(next);
visit[next.x][next.y]=1;
}
if(sum>T)return 0;
else if(map[next.x][next.y]=='D'&&sum==T)
{
flag=1;return 1;
}
else if(map[next.x][next.y]=='D'&&sum<T)
return 0;
}
}
}
if(flag==0) return 0;
}
int main()
{
int i,j,sx,sy,sun;
while(scanf("%d%d%d",&n,&m,&T)!=EOF)
{
if(n+m+T==0)break;
memset(visit,0,sizeof(visit));
memset(map,0,sizeof(map));
for(i=1;i<=n;i++)
{
getchar();
for(j=1;j<=m;j++)
{
scanf("%c",&map[i][j]);
if(map[i][j]=='S')
{sx=i;sy=j;}
}
}
sun=BFS(sx,sy);
if(sun==0)printf("No\n");
else printf("YES\n");
}
return 0;
}
如测试实例:
S.X.
.XD.
...X
...X
T=4;
可能路径是:'S'->(2,1)->(3,1)->(4,1)->(4,2)->(4,3)->(3,3)->'D'一共7七步,
还可能的路径是'S'->(2,1)->(3,1)->(3,2)->(3,3)->'D' 共4步;
如果先通过第一种到达了'D',由于(3,3)已被标记走过,所以会找不到符合条件的路径,不像深搜那样找不到,释放路径,可以返回去重找。