做DFS(或其他搜索题),我感觉最有趣的地方不是DFS本身而是——“剪枝”。剪枝,顾名思义就是剪去不必要的枝节,也就是避免不必要的搜索过程。有点类似于工程领域的“去噪”,当然这是个人感觉而已。。
HDU 1010这道题是一个典型的迷宫搜索题。给你出口入口,但是你并不是能找到出口就完事了。注意事项:
前面有篇博文《hdu1518》,已经提到了DFS的一般框架就是:循环+递归。
循环,是横着走。递归是竖着走。注意,我这里说的“横”和“竖”并不是对应本题中迷宫的物理意义上的横竖,而是关于 抽象的逻辑意义上的横 和竖。
本题中 的 横 是 某一结点周围的 上、下、左、右 四个方向。
本题中的 竖 就是递归搜索每一结点的 “横”。
终止态:是所走的步数(即题意中的时间)等于给出的时间。若此时还未走到出口,则返回fasle。找到出口则返回true。
本题中我没有使用一个[4][2]的二维数组来保存 上下左右 四个方位的移动。所以看起来代码有些繁琐,但是可读性却高。
bool dfs(int ti,int i,int j)
{
if(ti==t)//ti是当前步数,t是给出的步数,或者说时间
{
if(i==h&&j==w)
return true;
return false;
}
if(j<m-1&&!ma[i][j+1])
{
ti++;//步数+1
ma[i][j]=true;//迷宫中该点设为已走
if(ti<=t&&dfs(ti,i,j+1))
return true;
ti--;//若走此步最终失败了,那么就步数-1
ma[i][j]=false;//再设为该点未走,即回溯的过程
}
if(i<n-1&&!ma[i+1][j])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i+1,j))
return true;
ti--;
ma[i][j]=false;
}
if(i&&!ma[i-1][j])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i-1,j))
return true;
ti--;
ma[i][j]=false;
}
if(j&&!ma[i][j-1])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i,j-1))
return true;
ti--;
ma[i][j]=false;
}
return false;
}
本题代码简单但是很容易超时,所以要注意剪枝。
首先看理论上的最短路径。
int path = abs(si-h)+abs(sj-w);
(si,ji)、(h,w)分别为起点终点坐标。我们可使用的两种剪枝方案是:
关于第二种方案的解释:
这种方案学名为“奇偶剪枝”。我们已知了最短的步数就是直角三角形的两条直角边,实际上的路径却不一定非要沿着这两条边走的。仔细看看只要是移动方向一直是右、下,那么走到的时候总步数也一定是path的。然而由于墙的存在或许我们不可能一直右、下的走下去。为了避开墙,我们可能会向左走,向上走等等。但为了到达目的地,你在最短步数的基础上,如果向右走了一步,那么某一时候也必须再向左走一步来弥补。所以(t-path)一定要是2的倍数。
if(t<path||(t-path)%2)
{
cout<<"NO"<<endl;
continue;
}
看完整代码:
#include <iostream>
using namespace std;
bool ma[10][10];
int h,w;
int n,m,t;
bool dfs(int ti,int i,int j)
{
if(ti==t)
{
if(i==h&&j==w)
return true;
return false;
}
if(j<m-1&&!ma[i][j+1])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i,j+1))
return true;
ti--;
ma[i][j]=false;
}
if(i<n-1&&!ma[i+1][j])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i+1,j))
return true;
ti--;
ma[i][j]=false;
}
if(i&&!ma[i-1][j])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i-1,j))
return true;
ti--;
ma[i][j]=false;
}
if(j&&!ma[i][j-1])
{
ti++;
ma[i][j]=true;
if(ti<=t&&dfs(ti,i,j-1))
return true;
ti--;
ma[i][j]=false;
}
return false;
}
int main()
{freopen("in.txt","r",stdin);
while(cin>>n>>m>>t)
{
if(!n&&!m&&!t)
break;
memset(ma,false,sizeof(ma));
char c;
int si,sj;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>c;
switch(c)
{
case ‘S‘:si=i;sj=j;ma[i][j]=true;break;
case ‘.‘:ma[i][j]=false;break;
case ‘X‘:ma[i][j]=true;break;
case ‘D‘:ma[i][j]=false;h=i,w=j;break;
}
}
int path = abs(si-h)+abs(sj-w);
if(t<path||(t-path)%2)
{
cout<<"NO"<<endl;
continue;
}
if(dfs(0,si,sj))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
HDU 1010 DFS+奇偶剪枝,布布扣,bubuko.com
原文:http://blog.csdn.net/guodongxiaren/article/details/23172475