HDU 2531 Catch him(BFS:判断是否存在路径)
http://acm.hdu.edu.cn/showproblem.php?pid=2531
题意:
给你一个R*C的棋盘,但是现在不是一个格子移动了,而是多个格子组成的一个防守队员平移一个距离,但是这个组合防守队员格不可以转动身体,且身体不能触碰到O格子.最终只要身体能触碰到Q格子就算赢.
分析:
BFS的关键在于你设计一个结构保存棋牌的每一步状态,然后根据当前状态扩展出它的所有可行不重复后继状态.最终通过判断后继是否终态来结束BFS.
就拿这道题来说,棋牌上共4种点,但是只有D点是会动的,我们只需要保存下所有D点的坐标,即可完整保存整个棋盘的状态.所以采用如下结构来表示每个状态:
struct Node
{
int r[21],c[21];
int dist;
};
正常来说,D格子最多有20个,你要判重这种具有20个坐标的状态,只能用hash了,不可能设一个20维的vis数组来判重.但是这里要注意:D球员只能平移,也就是说D格子之间的相对位置是不变的,我们只要知道最左上角的D格子,其他D格子的位置就也知道了.所以我们只需要用一个vis[r][c]来判断防守球员最左上角的那个格子是否出现在(r,c)过即可.
AC代码:
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=105;
int dr[]={-1,1,0,0};
int dc[]={0,0,-1,1};
int R,C,size;
char map[maxn][maxn];
bool vis[maxn][maxn];
struct Node
{
int r[21],c[21];
int dist;
}start;
int BFS()
{
queue<Node> Q;
memset(vis,0,sizeof(vis));
Q.push(start);
while(!Q.empty())
{
Node node=Q.front(); Q.pop();
for(int d=0;d<4;d++)
{
int i;
Node p=node;
p.dist++;
for(i=0;i<size;i++)
{
p.r[i] += dr[d];
p.c[i] += dc[d];
if(p.r[i]<0||p.r[i]>=R||p.c[i]<0||p.c[i]>=C) break;
if(map[p.r[i]][p.c[i]]=='O') break;
}
if(i!=size) continue; //非法
if(vis[p.r[0]][p.c[0]]) continue;
for(i=0;i<size;i++) if(map[p.r[i]][p.c[i]]=='Q') return p.dist;
vis[p.r[0]][p.c[0]]=true;
Q.push(p);
}
}
return -1;
}
int main()
{
while(scanf("%d%d",&R,&C)==2&&R)
{
size=0;
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
{
scanf(" %c",&map[i][j]);
if(map[i][j]=='D')
{
start.r[size]=i;
start.c[size++]=j;
}
}
start.dist=0;
int ans=BFS();
if(ans==-1) printf("Impossible\n");
else printf("%d\n",ans);
}
return 0;
}
</span>