简单题意
输入给出准备擒杀四分卫的防守球员的位置、对方每个进攻锋线球员的位置以及对方四分卫的位置,你的任务是求出这名准备擒杀的防守球员至少要移动多少步,才能够擒杀对方四分卫。假设对方进攻锋线和四分卫在这个过程中都不会移动。只有1名防守球员,防守球员只要碰到对方四分卫就算擒杀。所有的球员都是一块连续的、不中空的2维区域。防守球员不可以从进攻锋线的身体上穿过,也不可以从界外穿过(只能走空地)。防守队员不可以转动身体,只能平移。防守队员的身体所有部分向同一个方向(上、下、左、右)移动1格的过程叫做1步。
解题思路形成过程
讲真看题都没看懂,不是很懂足球,去看看大神怎么说(服了这个题):将整体用 一个点x,y加上其他点的相对位移来表示,身体的每一个部分用一个数字来标记依次标为:1,2,3,4,5... 移动过程中,相同的标记点不能重复走过,也就是说,身体的某个部分走过的点,不能再走第二遍,而其他点可以,例如,第一个节点标记为1,它不能再走标记为1的点。好像就是广搜。
感想
读懂题好难,做为一个ACMer真的需要啥都知道
AC代码
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
char cmap[110][110]; //定义map
int mark[110][110]; //定义标记
struct Node
{
int x,y,step;
}d,p; //节点,注意节点只 存其中一个点即可
int bx[30],by[30]; //存有相对位置的数组
int cx[]={1,-1,0,0};
int cy[]={0,0,-1,1};
int bfs(int len,int m,int n,int x,int y)
{
int i,j;
queue<Node> q;
memset(mark,0,sizeof(mark));
d.x=x;
d.y=y;
d.step=0;
q.push(d);
for(i=0;i<len;i++)
mark[bx[i]][by[i]]=i+1; //用位置标记
while(!q.empty())
{
d=q.front();
q.pop();
for(i=0;i<len;i++)
if(cmap[d.x+bx[i]][d.y+by[i]]=='Q')
return d.step;
for(i=0;i<4;i++)
{
p.x=d.x+cx[i];
p.y=d.y+cy[i];
p.step=d.step+1;
//进行条件判断
for(j=0;j<len;j++)
{
int tx,ty;
tx=p.x+bx[j];
ty=p.y+by[j];
if(cmap[tx][ty]=='O'||tx<0||tx>=m||ty<0||ty>=n||mark[tx][ty]==j+1)
break;
}
if(j<len)
continue; //若是break出来的就不进入push和标记
q.push(p);
//标记
for(j=0;j<len;j++)
{
int tx,ty;
tx=p.x+bx[j];
ty=p.y+by[j];
mark[tx][ty]=j+1;
}
}
}
return 0;
}
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
if(!m&&!n)
break;
int i,j,k;
for(i=0;i<m;i++)
scanf("%s",cmap[i]);
for(k=i=0;i<m;i++)
for(j=0;j<n;j++)
{
if(cmap[i][j]=='D')
{
bx[k]=i;
by[k]=j;
k++;
}
}
int sx=bx[0],sy=by[0];
for(i=0;i<k;i++) //生成相对位置数组
{
bx[i]-=sx;
by[i]-=sy;
}
int ans=bfs(k,m,n,sx,sy);
if(ans)
printf("%d\n",ans);
else
puts("Impossible");
}
return 0;
}