传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1010
先枚举总步数,即开门周期的倍数,T,2*T,3*T,....iT<=总的可走方块数
如下代码:
for(int i = T;i<=block;i+=T){if(ok){break;}else dfs(st,0,i);}
然后进入dfs后各种剪枝:
if(ok)return;
if(u == en && num == iT){ok = 1;return;}///到达
if(num > iT)return;
int x = u/Nc,y = u%Nc;
if(abs(x-ex) + abs(y-ey)>iT-num)return;
if((iT - num - abs(x-ex) - abs(y-ey))%2)return;
各种剪枝:
已找到了一条路剪枝,当前步数超过总步数,剪枝
奇偶剪枝
已走步数+剩余最短路步数>iT剪枝
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int N = 30;
int Nr,Nc,T,block;
int st,en;
int ex,ey;
int ok;
int maps[N][N];
int vis[N][N];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int u,int num,int iT)
{
if(ok)return;
if(u == en && num == iT){ok = 1;return;}///到达
if(num > iT)return;
int x = u/Nc,y = u%Nc;
if(abs(x-ex) + abs(y-ey)>iT-num)return;
if((iT - num - abs(x-ex) - abs(y-ey))%2)return;
for(int i = 0;i<4;i++){
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if(newx>=0 && newx<Nr && newy>=0 && newy <Nc && !maps[newx][newy] && !vis[newx][newy]){
int newu = newx*Nc + newy;
vis[newx][newy] = 1;
dfs(newu,num+1,iT);
vis[newx][newy] = 0;
}
}
}
int main()
{
char s[N];
char a;
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&Nr,&Nc,&T) == 3){
a = getchar();
if(Nc == 0 && Nr == 0 && T == 0)break;
memset(vis,0,sizeof(vis));
ok = 0,block = 2;
for(int i = 0;i<Nr;i++){
scanf("%s",s);
for(int j = 0;j<Nc;j++){
if(s[j] == 'S'){vis[i][j] = 1;maps[i][j] = 0;st = i*Nc + j;}
else if(s[j] == '.'){maps[i][j] = 0;block++;}
else if(s[j] == 'X'){maps[i][j] = 1;}
else if(s[j] == 'D'){maps[i][j] = 0;ex = i,ey = j;en = i*Nc + j;}
}
}
for(int i = T;i<=block;i+=T){if(ok){break;}else dfs(st,0,i);}
if(ok)printf("YES\n");
else printf("NO\n");
}
return 0;
}