题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010
一开始做这道题的时候想的是BFS,但是一直WA,看好题目才知道是要在指定的时间内正好到此处,则利用DFS+奇偶剪枝来进行解题:
奇偶剪枝:https://baike.sogou.com/v72712602.htm?fromTitle=奇偶剪枝
在没有障碍物的一个矩形中,一个点到另外一个点之间的最短距离为:min=Math.abs(sx-dx)+Math.abs(sy-dy)为其两点之间的坐标的差。
如:
S 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 D
其最短路径为:min=9;
当头节点和尾节点不变,在原来的基础上加上一些阻碍
S 1 1 1 X X
X X X 1 X X
1 1 1 1 X X
1 X X X X X
1 1 1 1 1 D
X为障碍,则其最短路径为:minX=15;
则minX=min+6;
不管图是怎么样的,只要有通路对他们进行连接,则他们之间的差值都为一个偶数,这个为结论。
则奇偶剪枝就是把一些已经没有必要的枝条给减掉,不用再继续执行下去。
该剪掉的枝条:
设置:min为其没有阻碍时的最小路径; step为其从起点开始走,走到第几步的路径;minX为其实质走的路径。
1:首先判断可走的路径的长度是否满足要走的路数,如果不满足,剪掉(.的数目是否满足要走的路数)如果不满足直接输出NO
2:判断起点坐标和终点坐标之间的最短距离min是否比给出的路径小,如果比其大,则不满足,输出NO
3:判断奇偶性质,(minStep+step-min)%2==0判断是否为偶数,如果不是偶数的话则剪去,其中minStep的值为当前走到的坐标距离终点之间的的最短路径。
4:当step+minStep的值大于给出的路径长度,则表示再继续走下去也没有用了,因为剩下的最短路径都到不了,就别想到了,则剪掉。
下面为AC代码:
public class Pid1010 {
static int row;
static int colum;
static int fin;
static int sx,sy,dx,dy;
static int[][] dex= {{1,0},{0,1},{-1,0},{0,-1}};
static char[][] data;
static boolean[][] marked;
static int ant;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
row = sc.nextInt();
colum = sc.nextInt();
fin = sc.nextInt();
sc.nextLine();
if(row==0&&colum==0&&fin==0)
break;
marked = new boolean[row][colum];
data = new char[row][colum];
int count=0;
for(int i=0;i<row;i++) {
String str = sc.next();
data[i]=str.toCharArray();//输入数据
for(int j=0;j<colum;j++) {
if(data[i][j]=='D'||data[i][j]=='d') {
dx=i;
dy=j;
}else if(data[i][j]=='.')
count++;
else {
if(data[i][j]=='S'||data[i][j]=='s') {
sx=i;
sy=j;
}
}
}
}
ant = Math.abs(sx-dx)+Math.abs(sy-dy);//起点和终点之间的最短路径
marked[sx][sy]=true;
if(count+1<fin||ant>fin)//剪枝条件,.的数目满足不了给出的路径,最短路劲ant比需要走的路径还要大,剪掉
System.out.println("NO");
else {
if(dfs(sx,sy,0))//分别为起点的横坐标,起点的纵坐标,和步数。
System.out.println("YES");
else System.out.println("NO");
}
}
}
private static boolean dfs(int tempx, int tempy, int step) {
if((data[tempx][tempy]=='D'||data[tempx][tempy]=='d')&&step==fin) {//当步数正好为需要的路径长度的时候,则满足
return true;
}
for(int i=0;i<4;i++) {//四个方向进行判断
boolean temp = true;
int a = tempx+dex[i][0];
int b = tempy+dex[i][1];
if(a<0||a>=row||b<0||b>=colum||marked[a][b]||data[a][b]=='X'||data[a][b]=='x')
continue;
int minStep = Math.abs(tempx-dx)+Math.abs(tempy-dy);//当前点距离终点之间的最短路径
if(minStep>fin-step||(step+minStep-ant)%2!=0) //当前点距离终点的最短路径比需要走的路径长度减去已经走了步数还要长则剪去,奇偶性,不为偶数的话则剪去。
temp=false;
if(!temp)
continue;
if((data[a][b]=='d'||data[a][b]=='D')&&step!=fin-1)//如果D这个坐标被打true了的话则不会访问了
continue;
marked[a][b]=true;
if(dfs(a,b,step+1))return true;
marked[a][b]=false;
}
return false;
}
}