您的位置:首页 > Web前端

hdu 5024 Wang Xifeng's Little Plot【暴力dfs,剪枝】

2014-09-20 20:07 375 查看
2014年广州网络赛的C题,也是水题。要你在一个地图中找出一条最长的路,这条路要保证最多只能有一个拐角,且只能为90度

我们直接用深搜,枚举每个起点,每个方向进行dfs,再加上剪枝。

但是如果直接写的话,那一定会特别麻烦,再加上方向这一属性也是我们需要考虑的方面,我们将从别的地方到当前点的方向编一个号:往右为0,如下图顺时针顺序编号


(往右下方向为1,往下为2......以此类推)

我们知道了当前点的坐标,来到当前点的方向,以及到目前有没有拐弯,这几个属性之后,就可以记忆化搜索了,用一个四维数组dp[][][][]实现。

下面,我们还需要知道从某个方向来到这个点,我们下一步能走到什么位置,比如我上次是往右来到这个点,那么我下次就只能往上或者往下,或者继续往右走。也就是说,每次其实只能走三个方向。再用一个数组记录一下这三个数字,那么代码就能缩短很长了。那怎么记录?

还是一样,我们将每个点的附近八个点分别编号,方向数组大家应该都知道吧,用一个数组加一个循环模拟八个方向的移动。有了这个数组,我们就可以很方便的记录上述所说的东西了。

详见代码:

#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#define N 110
using namespace std;
int n,dp

[9][2],ans,dx[]= {-1,-1,-1,0,0,1,1,1},dy[]= {-1,0,1,-1,1,-1,0,1};
int D[8][3]= {{1,6,4},{2,5,7},{3,4,6},{0,7,5},{1,6,3},{2,5,0},{3,4,1},{0,7,2}};//每个方向过来,我能移动到相对当前点的哪几个点。里面的数对应方向数组的下标,每个方向对应的前两个元素代表需要转角,第三个元素代表直线移动。
int fr[8][2]= {{6,2},{7,3},{4,0},{5,1},{6,2},{7,3},{4,0},{5,1}};//代表我转角的话,到达相对当前点的那个点。
char a

;
int dfs(int ix,int jx,int dir,int w)//ix,jx代表当前坐标,dir代表上一个点到这个点的方向,w代表是否已转向
{
if(dp[ix][jx][dir][w]!=-1) return dp[ix][jx][dir][w];//记忆话搜索
int tmp=1;//初始化为1
for(int i=0; i<3; i++)
{
int u=D[dir][i];
int x=ix+dx[u],y=jx+dy[u];
if(x>=0 && x<n && y>=0 && y<n && a[x][y]=='.')
{
if(i==2)
{
tmp=max(tmp,dfs(x,y,dir,w)+1);
}
else if(w==0)
{
tmp=max(tmp,dfs(x,y,fr[dir][i],1)+1);
}
}
}
return dp[ix][jx][dir][w]=tmp;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
ans=0;
memset(dp,-1,sizeof(dp));
for(int i=0; i<n; i++)
scanf("%s",a[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
if(a[i][j]=='#') continue ;//遍历每个不是#的点作为起点,作为起点,所以八个方向都要遍历。
for(int k=0; k<8; k++)
{
dfs(i,j,k,0);
}
}
}
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
for(int k=0; k<8; k++)
for(int l=0; l<2; l++)
ans=max(ans,dp[i][j][k][l]);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: