http://acm.hdu.edu.cn/showproblem.php?pid=1010
一开始看7*7以为不需要进行剪枝结果。妥妥的超时了。。跑去学习了下奇偶剪枝法。。主要的思想就是当前点到终点所要走的距离应该是他们之间的最短距离加上一个偶数的距离。。不可能是一个奇数。。奇数+偶数=奇数 偶数+偶数=偶数。 所以就能判断总时间必须和最短距离必须同奇偶。。这还可以推广到迷宫中的每一步,对于每一步来说剩下的时间和剩下的最短距离必须是同奇偶。。奇数-奇数=偶数 偶数-偶数=偶数。
那么这题就可以运用两个剪枝。
1、判断剩下的时间 - 剩下的最短距离是否小于零,如果是,必不能抵达(当然这也包含了剩下时间小于零的情况)
2、判断剩下的时间 - 剩下的最短距离是否为偶数,如果是,就能代表他们两个同奇偶,就有可能到达。
背景:在写这道题的过程中我还发现了,自己会犯的一个小错误。。就是剪枝后如果不满足要回溯,在回溯之前应该要将这个点的标记取消,避免之后这个点无法走。。
代码:
//可以写为注释这种写法,就不需要对起点进行标记,但是在剪枝后回溯之前要记得进行还原标记
//也可以写成在进入dfs前后进行标记跟还原,但是这样无法对起点进行标记,要记得在主程序中进行对起点的标记
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,t;
int d1[4] = {0,0,1,-1};
int d2[4] = {1,-1,0,0};
bool visit[10][10];
char map[10][10];
int sx,sy,ex,ey;
int ok ;
void dfs(int x,int y,int time)
{
//visit[x][y] = true;
if(ok==1) return ; //注意找到答案后要返回
int temp = t-time-(abs(ex-x)+abs(ey-y));
if(temp<0||temp%2!=0)
{
//visit[x][y] =false;
return ;
}
if(x==ex && y==ey && time==t)
{
ok = 1;
cout << "YES\n";
return;
}
for(int i = 0;i < 4;i++)
{
int dx = x+d1[i];
int dy = y+d2[i];
if(dx>=0&&dx<n&&dy>=0&&dy<m&&map[dx][dy]!='X'&&!visit[dx][dy])
{
visit[dx][dy] = true;
dfs(dx,dy,time+1);
visit[dx][dy] = false;
}
}
//visit[x][y] = false;
}
int main()
{
while(cin >> n >> m >> t && (n||m||t))
{
ok = 0;
memset(visit,0,sizeof(visit));
for(int i = 0;i < n;i++)
{
for(int j = 0;j < m;j++)
{
cin >> map[i][j];
if(map[i][j]=='S')
{
sx = i;
sy = j;
}
if(map[i][j]=='D')
{
ex = i;
ey = j;
}
}
}
visit[sx][sy] = true; //写为注释那种写法就不需要标记起点
dfs(sx,sy,0);
if(!ok) cout << "NO\n";
}
}