小狗在一个古老的迷宫中发现了一块骨头,这让他很着迷。然而,当他拿起它时,迷宫开始摇晃,小狗可以感觉到地面下沉。他意识到骨头是一个陷阱,他拼命想要摆脱这个迷宫。
迷宫是一个大小为N×M的矩形。迷宫中有一扇门。在开始时,门被关闭,它将在第T秒开启一小段时间(不到1秒)。因此,小狗必须在第T秒才到达门口。在每一秒中,他可以将一个块移动到上,下,左和右相邻块之一。一旦他进入一个区块,这个区块的地面将开始下沉并在下一秒消失。他不能在一个街区停留一秒以上,也不能进入一个被访问的街区。这只可怜的小狗能活下来吗?请帮帮他。
输入包含多个测试用例。每个测试用例的第一行包含三个整数N,M和T(1 <N,M <7; 0 <T <50),分别表示迷宫的大小和门打开的时间。 。接下来的N行给出迷宫布局,每行包含M个字符。角色是下列之一:
'X':一块墙,小狗不能进入;
'S':小狗的起点;
'D':门; 或
'.':空块。
输入以三个0结束。不处理此测试用例。
这个写的不错:1010 temp of the bone 解题报告
N 行 M 列 T 时间,看这个doggie是否能在第T秒刚好到达门。S是doggie的起始位置,D是门的位置。
一开始我对这个时间T有点不理解,拿题目中例2来说S走4步在D的前一个位置,再走一步到达D,题目是要在5秒刚好在D,而不是所谓的在时间T内到达就行了。
这道题里涉及一些剪枝问题,如果不剪枝就会超时。(我们来把这道题的迷宫想象成一块一块的格子)。
①n*m-wall<=t . n*m代表总共的格子,n*m-wall代表能走的格子数目,t是时间,n*m-wall<=t也就是可以走的格子走完了时间T都没有到,肯定不能到达D。至于为什么有=,看的一个大佬写的一个例子:
3 3 4
S X X
. X X
X . D 在这里n*m-wall=3*3-5=4=t,这里是不能到达的。
②奇偶剪枝
因为两点之间直线最短,所以由S到达D的最短路径就是abs(sx-dx)+abs(sy-dy),可以把t理解为题目要你走的总步数,t-step就代表你任意走的总步数,因为abs(sx-dx)+abs(sy-dy)已经是最短的步数了,你走的一定不可能比它更短,所以t-step肯定是要>=最短步数的。所以当t-step<abs(sx-dx)+abs(sy-dy)的时候,我们就给它剪出去。(注意sx,sy,step都是在变化的)
还有t-step-abs(sx-dx)-abs(sy-dy)必须是偶数,如果是奇数就不能到达D,给个例子大家看看吧
3行4列 最短距离是5。红色箭头代表随意走的路线,一共9步,9-5=4为偶数,刚好到达D,如果为奇数,那最后一步到达的肯定是D的周围而不能刚好到达D。
一开始不会剪枝,看了博客,学会了奇偶剪枝+路径剪枝,还有别忘记标记起点的vis[x1][y1]
import java.util.Scanner;
public class hdu1010 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()) {
n = in.nextInt();
m = in.nextInt();
T = in.nextInt();
if(n==0)
break;
vis = new boolean[n][m];
ch = new char[n][m];
flag = false;
wall = 0;
x1=y1=-1;
for(int i=0;i<n;i++)
ch[i] = in.next().toCharArray();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(ch[i][j]=='S') {
x1 = i;
y1 = j;
}else if(ch[i][j]=='D') {
x2 = i;
y2 = j;
}else if(ch[i][j]=='X')
wall++;
if(n*m-wall<=T) {//路径剪枝
System.out.println("NO");
continue;
}
vis[x1][y1] = true;
dfs(x1,y1,0);
if(flag)
System.out.println("YES");
else
System.out.println("NO");
}
}
static int n,m,T,x1,y1,x2,y2,wall;
static boolean[][] vis;
static char[][] ch;
static boolean flag;
static int[] dx = new int[] {1,0,-1,0};
static int[] dy = new int[] {0,1,0,-1};
static void dfs(int x,int y,int t) {
if(ch[x][y]=='D') {
if(t==T)
flag = true;
return;
}
int p = T - t - (Math.abs(x-x2)+Math.abs(y-y2));//剩余步-最短路径判断
if(p<0 || p%2==1)//奇偶剪枝 p只能为偶数
return;
for(int i=0;i<4;i++)
if(ok(x+dx[i],y+dy[i])) {
vis[x+dx[i]][y+dy[i]] = true;
dfs(x+dx[i],y+dy[i],t+1);
vis[x+dx[i]][y+dy[i]] = false;
if(flag)//找到答案就结束所有在搜索的路径
return;
}
}
static boolean ok(int x,int y) {
return x>=0 && x<n && y>=0 && y<m && ch[x][y]!='X' && !vis[x][y];
}
}