Catch him
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 771 Accepted Submission(s): 349
对防守方来说,攻击对手的四分卫当然是最直接的限制对手进攻的方法。如果效果好,就可以在对方四分卫传球之前将其按翻在地,称之为擒杀。擒杀是最好的鼓舞防守队士气的方法,因为对方连传球的机会都没有,进攻就结束了,还必须倒退一些距离开球。凶狠的擒杀甚至能够将对方的四分卫弄伤,从而迫使对方更换这个进攻核心。
在本题中,输入给出准备擒杀四分卫的防守球员的位置、对方每个进攻锋线球员的位置以及对方四分卫的位置,你的任务是求出这名准备擒杀的防守球员至少要移动多少步,才能够擒杀对方四分卫。
假设对方进攻锋线和四分卫在这个过程中都不会移动。只有1名防守球员,防守球员只要碰到对方四分卫就算擒杀。
所有的球员都是一块连续的、不中空的2维区域。防守球员不可以从进攻锋线的身体上穿过,也不可以从界外穿过(只能走空地)。
防守队员不可以转动身体,只能平移。防守队员的身体所有部分向同一个方向(上、下、左、右)移动1格的过程叫做1步。
输入保证符合上面的条件。防守球员的身体总共不超过20格。
6 6
.Q....
QQ..OO
.OO..O
...O.O
OO.O..
....DD
7 7
.Q.....
QQ.OOO.
...O...
O......
OO..OO.
.O.....
.....DD
0 0
Sample Output
Impossible
9
中文题意,图搜。
解题过程+大体思路:
首先我们移动的是一个由好多格子或者单个格子组成的一个D(防守队员)。如果我们每一个点都进行移动的话未免有点太尴尬,而且vis【】【】判断是否走过该点的判断也不是很好写,这个时候我们需要一个抽象的想法:我们把这一坨D的最先出现的D(两层for遍历的情况下)当做一个头,我们移动头即可,那么我们怎样细节上处理这个题目呢?
如果我们有了一个标尺:“头” 之后呢,我们vis【】【】数组也就好处理了,对于头走过的点,标记上即可,那么他的身子要怎样移动呢?
我们都学过一个名词叫做:“相对”,关系可以相对,力可以相对,那么位子也可以相对。
对于这样的一个图:
ODO
ODO
ODD
我们规定第一个出现的D也就是坐标为(0,1)的点作为这个一坨D的头,我们可以通过头这样找到其他的身体部分:
(0,1)+(1,0)=(1,1)找到第二个出现的D,(0,1)+(2,0)=(2,1)找到第三个出现的D,(0,1)+(2,1)=(2,2)找到最后一个D。
那么我们可以通过保存(1,0)(2,0)(2,1)这三个x,y的相对位子值来通过“头”找到他们的身子。
这个时候小问题处理完毕了,我们就可以确定答题思路了:
用头漫无目的的BFS,每一次找到一个能走的位子都判断一下身子能否也可以达到相对位子,当然我们的“头”找到了Q的时候不要直接输出步数,我们还要判断他的身子能否走到合法的位子。同理,如果“身子”找到了Q的时候也不要直接输出步数,我们要确定所有身子的组成都能走到合法的位子才行,这个时候我们就不难写出代码:
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct zuobiao
{
int x,y,step;
}now,nex;
int n,m;
int cont;
int fang[25][2];
int vis[120][120];
char a[120][120];
int fx[4]={0,0,1,-1};
int fy[4]={-1,1,0,0};
void BFS(int x,int y)
{
memset(vis,0,sizeof(vis));
vis[x][y]=1;
queue<zuobiao >s;
now.x=x;
now.y=y;
now.step=0;
s.push(now);
while(!s.empty())
{
now=s.front();
//printf("%d %d\n",now.x,now.y);
s.pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+fx[i];
nex.y=now.y+fy[i];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[nex.x][nex.y]==0&&a[nex.x][nex.y]!='O')//左上角的头一定要合法才行
{
if(a[nex.x][nex.y]=='Q')//如果头遇到了Q
{
int ok=1;
for(int j=0;j<cont;j++)//那么要判断其他身体部分都合法。
{
int xx=nex.x+fang[j][0];
int yy=nex.y+fang[j][1];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]!='O')continue;
ok=0;
}
if(ok==1)
{
printf("%d\n",now.step+1);
return ;
}
}
int ok=1;
int flag=0;
for(int j=0;j<cont;j++)
{
int xx=nex.x+fang[j][0];
int yy=nex.y+fang[j][1];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]=='Q')//如果某个身子的部分碰到了Q,这个时候不要break,也要继续判断其他身子是否合法。
{
flag=1;
}
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]!='O')continue;
ok=0;
}
if(ok==1&&flag==1)
{
printf("%d\n",now.step+1);
return ;
}
if(ok==1)
{
vis[nex.x][nex.y]=1;
nex.step=now.step+1;
s.push(nex);
}
}
}
}
printf("Impossible\n");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)break;
cont=0;
int sx,sy;
for(int i=0;i<n;i++)
{
scanf("%s",a[i]);
for(int j=0;j<m;j++)
{
if(a[i][j]=='D')
{
if(cont==0)sx=i,sy=j,cont=1;//找到头
else
{
fang[cont][0]=i-sx;//记录身子的相对位子
fang[cont][1]=j-sy;
cont++;
}
}
}
}
//printf("%d\n",cont);
BFS(sx,sy);
}
}