题目链接:点击打开链接
题目大意为:给定一个n*m的矩阵和起点到终点的应该走的步数countMax,S为起点,D为终点, .为路求有没有一条路可以刚好经过countMax步到达终点
我做这个题目的时候,前面就是看成一个普通的DFS题,没想什么超时的问题,后来才发现按照普通的DFS去做会超时,于是我开始剪枝,参考了点击打开链接百度百科的奇偶剪枝。才解决了超时的问题。
奇偶剪枝的描述如下:
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s
| ||||
|
| ||||
|
| ||||
|
| ||||
+
|
—
|
—
|
—
|
e
|
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
s
|
—
|
—
|
—
| |
—
|
—
|
+
| ||
|
|
+
| |||
|
| ||||
+
|
—
|
—
|
—
|
e
|
如图,为一般情况下非
最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证);
设t为要求到达的步数
则,若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;
返回,false;
反之亦反。
原理补充可以,参考百度百科链接:
点击打开链接
代码实现如下:
package acm;
import java.util.Scanner;
public class P1010 {
public static int f[][]={{0,-1},{0,1},{-1,0},{1,0}};
public static int n,m,countMax;
public static char a[][];
public static boolean color[][];
public static boolean t;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
n=sc.nextInt();
m=sc.nextInt();
countMax=sc.nextInt();
if(n==0&&m==0&&countMax==0){
break;
}
color=new boolean[n][m];
a=new char[n][m];
String b[]=new String[n];
int x1=-1,y1=-1,x2=-1,y2=-1;
for(int i=0;i<n;i++){
b[i]=sc.next();
a[i]=b[i].toCharArray();
for(int j=0;j<a[i].length;j++){
color[i][j]=true;
if(a[i][j]=='S'){//记录S的位置
x1=i;
y1=j;
}
if(a[i][j]=='D'){//记录D的位置
x2=i;
y2=j;
}
}
}
if((countMax-Math.abs(x2-x1)-Math.abs(y2-y1))%2==1){
//奇偶剪枝
System.out.println("NO");
continue;
}
t=false;
color[x1][y1]=false;
dfs(x1,y1,0);
if(t){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
public static void dfs(int x,int y,int count){
if(count>countMax){
return;//当走过的步数超过了要求的步数,return
}
if(t){
return;//当标记为真,return
}
if(count==countMax&&a[x][y]=='D'){
t=true;//当刚好走到'D'且走过的步数等于要求的步数
return;
}
for(int i=0;i<4;i++){
//遍历该位置的四个方向
int nx=x+f[i][0];
int ny=y+f[i][1];
if(nx>=0&&ny>=0&&nx<n&&ny<m){
if(color[nx][ny]&&(a[nx][ny]=='.'||a[nx][ny]=='D')){
color[nx][ny]=false;
dfs(nx,ny,count+1);
color[nx][ny]=true;//回溯
}
}
}
}
}