题意:输入一个n*m的迷宫,和一个T:可以在迷宫中生存的最大时间。S为起点,D为终点。并且,每个格子只能踩一次,且只能维持一秒,然后该块地板就会塌陷。所以你必须每秒走一步,且到D点时,所用时间为T。用深搜。
之前,误以为就是找到最短路,结果不是,而是恰好T秒走出迷宫。用DFS,超时可见剪枝的重要。
这题的剪枝主要是两个方面。
1:利用曼哈顿距离剪枝 —– 算出终点到该点的距离,与剩余的时间进行比较,如果到终点的距离大于剩余的时间,很明显是不能到达的。
2:利用奇偶剪枝 —- 如果二者之间距离与剩余时间的差是奇数,那么就舍掉,因为当二者的差值是0时可以刚好到达,当二者的差值大于0时,就必须绕个远路拐两个直角到达,而此时必须是偶数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
int n,m,T;
const int N = 10;
char Map[N][N];
bool vis[N][N];
bool ans;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int edx,edy;
void DFS(int x,int y,int t)
{
if(x==edx && y==edy && t==T) {ans=true;return;}
if(t>=T) return;
if(x==edx && y==edy) return;
int dis=T-(fabs(edx-x)+fabs(edy-y)+t);//剪枝处
if(dis<0 ||dis%2 ) return;
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx<1||xx>n) continue;
if(yy<1||yy>m) continue;
if(Map[xx][yy]=='X' ||!vis[xx][yy]) continue;
vis[xx][yy]=false;
DFS(xx,yy,t+1);
if(ans) return;
vis[xx][yy]=true;
}
return;
}
int main()
{
while((scanf("%d %d %d",&n,&m,&T))!=EOF)
{
if(n==0 &&m==0 && T==0) break;
int x,y;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf(" %c",&Map[i][j]);
if(Map[i][j]=='S')
x=i,y=j;
if(Map[i][j]=='D')
edx=i,edy=j;
}
ans=false;
memset(vis,true,sizeof(vis));
vis[x][y]=false;
DFS(x,y,0);
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}
HDU 1175
题意就是我们平时玩连连看的意思,然后只能转两个弯,不能从外围走。
然后用DFS很残酷的TLE了。后来才想到一个剪枝点。
剪枝处:用vis的二维数组来存储当前的转弯数的情况,当前(i,j)这个点的转弯数大于vis[i][j]的时候,我们就return,因为vis[N][N]存储的是全局的最优解,这真是个大大的剪枝处。将标记数组的功能用的淋漓尽致,以后要记着点。
ps:剪枝来源:http://blog.csdn.net/iaccepted/article/details/24023215;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000+10;
int Map[N][N];
int vis[N][N];
int n,m,edx,edy;
bool flag;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void dfs(int x,int y,int cnt,int aim)
{
if(flag) return;
if(x<1||y<1||x>n||y>m||cnt>2) return;
if(x==edx && y==edy && cnt<=2) {flag=true;return;}
if(Map[x][y]!=0) return;
if(vis[x][y]!=-1&&vis[x][y]<=cnt) return;//剪枝处
vis[x][y]=cnt;
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(i==aim) dfs(xx,yy,cnt,i);
else dfs(xx,yy,cnt+1,i);
}
}
int main()
{
//freopen("test.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d %d",&n,&m))
{
if(n==0 &&m==0) break;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&Map[i][j]);
int Q;
scanf("%d",&Q);
while(Q--)
{
int x,y;
flag=false;
scanf("%d %d %d %d",&x,&y,&edx,&edy);
if(x<1||x>n||y<1||y>m||edx<1||edx>n||edy<1||edy>m||(x==edx&&y==edy)) {printf("NO\n");continue;}
if(Map[x][y]!=Map[edx][edy]||Map[x][y]==0 ||Map[edx][edy]==0) {printf("NO\n");continue;}
memset(vis,-1,sizeof(vis));
vis[x][y]=0;
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0];
int yy=y+dir[i][1];
dfs(xx,yy,0,i);
if(flag) break;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
未完待续 :)