Rday8

Rday8

BFS

Catch him

在美式足球中,四分卫负责指挥整只球队的进攻战术和跑位,以及给接球员传球的任务。四分卫是一只球队进攻组最重要的球员,而且一般身体都相对比较弱小,所以通常球队会安排5-7名大汉来保护他,其中站在四分卫前方、排成一线的5名球员称为进攻锋线,他们通常都是135公斤左右的壮汉。
对防守方来说,攻击对手的四分卫当然是最直接的限制对手进攻的方法。如果效果好,就可以在对方四分卫传球之前将其按翻在地,称之为擒杀。擒杀是最好的鼓舞防守队士气的方法,因为对方连传球的机会都没有,进攻就结束了,还必须倒退一些距离开球。凶狠的擒杀甚至能够将对方的四分卫弄伤,从而迫使对方更换这个进攻核心。
在本题中,输入给出准备擒杀四分卫的防守球员的位置、对方每个进攻锋线球员的位置以及对方四分卫的位置,你的任务是求出这名准备擒杀的防守球员至少要移动多少步,才能够擒杀对方四分卫。
假设对方进攻锋线和四分卫在这个过程中都不会移动。只有1名防守球员,防守球员只要碰到对方四分卫就算擒杀。
所有的球员都是一块连续的、不中空的2维区域。防守球员不可以从进攻锋线的身体上穿过,也不可以从界外穿过(只能走空地)。
防守队员不可以转动身体,只能平移。防守队员的身体所有部分向同一个方向(上、下、左、右)移动1格的过程叫做1步。

Input

1
2
输入包含多组数据。每组数据第一行都是两个整数H,W(0<H,W<=100),表示整个区域的高度和宽度,H=W=0表示输入结束。接下来有H行,每行W个字符。每个字符如果是’.’,表示这里是空地,如果是’O’,表示是进攻锋线队员的身体,如果是’D’,表示是准备擒杀的防守球员的身体,如果是’Q’,表示是四分卫的身体。
输入保证符合上面的条件。防守球员的身体总共不超过20格。

Output
对每组数据,输出包含擒杀所需最少步数的一行。如果不能擒杀,输出带’Impossible’的一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Sample Input
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的时候也不要直接输出步数,我们要确定所有身子的组成都能走到合法的位子才行

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int maxx = 1e3;

struct node{
int x, y, step;
}now, nex;
int n, m;
int cnt;
int fang[25][2];
char a[maxx][maxx];
int vis[maxx][maxx];
int d[4][2] = {
1, 0,
-1, 0,
0, 1,
0, -1
};

void bfs(int x, int y)
{
memset(vis, 0, sizeof vis);
vis[x][y] = 1;
queue<node> q;
now.x = x;
now.y = y;
now.step = 0;
q.push(now);
while(!q.empty())
{
now = q.front();
q.pop();
for(int i = 0; i < 4; i ++)
{
nex.x = now.x + d[i][0];
nex.y = now.y + d[i][1];
if(nex.x >= 0 && nex.y >= 0 && nex.x < n && nex.y < m && vis[nex.x][nex.y] == 0 && a[nex.x][nex.y] != 'O')
{
//找到头部
if(a[nex.x][nex.y] == 'Q')
{
int flag = 1;
//找头部附近的其他身体部分 并且判断是否合法
for(int j = 0; j < cnt; j ++)
{
int xx = nex.x + fang[j][0];
int yy = nex.y + fang[j][1];
if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != 'O') continue;
flag = 0;//不合法
}
if(flag)
{
cout << now.step + 1 << '\n';
return ;
}
}
int flag = 1;
int flag1 = 0;
for(int j = 0; j < cnt; j ++)
{
int xx = nex.x + fang[j][0];
int yy = nex.y + fang[j][1];
//如果某个身子的部分碰到了Q,这个时候不要break,也要继续判断其他身子是否合法。
if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] == 'Q') flag1 = 1;
if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != 'O') continue;
flag = 0;
}
if(flag == 1 && flag1 == 1)
{
cout << now.step + 1 << '\n';
return ;
}
if(flag)
{
vis[nex.x][nex.y] = 1;
nex.step = now.step + 1;
q.push(nex);
}
}
}
}
printf("Impossible\n");
}


int main()
{
while(~scanf("%d %d",&n, &m))
{
if(n == 0 && m == 0)
break;
cnt = 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(cnt == 0)
{
sx = i;
sy = j;
cnt = 1;
}
else
{
//记录身体的其他部分
fang[cnt][0] = i - sx;
fang[cnt][1] = j - sy;
cnt ++;
}
}
}
}
bfs(sx, sy);
}

return 0;
}

---------------- The End ----------------
0%