题目大意
你有一台割草机可以割除所有的杂草。最初,你站在 n × m ( n , m ≤ 150 ) n \times m(n,m \le 150) n×m(n,m≤150) 的花园的左上角(即在方格(1,1)处),花园的每一个方格用 a i , j a_{i,j} ai,j 表示。在任何时刻,你都面临着某个方向——左或右。最初,你面对右。
在一个步骤中,您可以执行以下任一操作:
- 向面向的方向移动一格
- 向下移动一格,并同时改变方向
如果你和你的割草机站在含有杂草的方格中(你的方向无关紧要),杂草就会被修剪掉。此操作不算作动作。问割除所有杂草所需的最小移动次数是多少?
杂草用 W
表示
样例输入
4 5
GWGGW
GGWGG
GWGGG
WGGGG
样例输出
11
样例解释
思路
显而易见,我们的路线图一定是一个类似蛇形的形状。而我们将其分成横向移动(不改变方向) 与纵向移动。
横向移动
对于每一行的最左边一个含有 w
的点(记作
l
i
l_i
li)以及 每一行的最右边一个含有 w
的点(记作
r
i
r_i
ri),显而易见
l
i
l_i
li 和
r
i
r_i
ri 必然有一个是另一个得来,因为已经到了第
i
i
i 行不可能再向上移动。因此对于每一行,我们只需要考虑最外侧的两个为 W
的点,而无需考虑中间的 W
。
我们用 y y y 表示现在在第 y y y 列, a n s ans ans 表示现在移动了 a n s ans ans 格。显而易见,如果现在是奇数排( i m o d 2 = 1 i \mod 2 = 1 imod2=1),那么朝右移动到 y 1 y1 y1。则 a n s ← a n s + y 1 − y , y ← y 1 ans \gets ans + y1 - y,y \gets y1 ans←ans+y1−y,y←y1;否则,则向左移动到 y 1 y1 y1, a n s ← a n s + y − y 1 , y ← y 1 ans \gets ans + y - y1,y \gets y1 ans←ans+y−y1,y←y1。显而易见, y 1 y1 y1 一定不会小于 r i r_i ri,因此 y 1 ← r i y1 \gets r_i y1←ri。
加入纵向移动后的影响
考虑以下情况
2 4
GGWG
GGGW
如果我们移动到 r 1 r_1 r1 再向下,那么第二行的最右边无法割除。所以在 i m o d 2 = 1 i \mod 2 = 1 imod2=1 时, y 1 ← max ( r i , r i + 1 ) y1 \gets \max(r_i,r_i + 1) y1←max(ri,ri+1),否则 y 1 ← min ( l i , l i + 1 ) y1 \gets \min(l_i,l_i + 1) y1←min(li,li+1)。因此,我们预处理 l , r l,r l,r 时,一定要注意。同时记得移动到下一行时记得 a n s ← a n s + 1 ans \gets ans + 1 ans←ans+1。
坑点
- 如果接下来的行中没有
W
,就直接输出当前答案,不需要再向下。
// 判断函数
bool check(int x) {
for(int i = x;i <= n;i++) if(r[i]) return false;
return true;
}
- 有时候在偶数行,会出现 m i n ( l 2 i , l 2 i + 1 ) > y min(l_{2i},l_{2i + 1}) > y min(l2i,l2i+1)>y 的情况,如以下情况的第四行:
5 4
GGGW
GGGG
WGGG
GGGG
GGWG
因此,我们最好要让
y
1
=
m
i
n
(
y
,
l
2
i
,
l
2
i
+
1
)
y1 = min(y,l_{2i},l_{2i + 1})
y1=min(y,l2i,l2i+1)
奇数行同理。
代码
#include<bits/stdc++.h>
using namespace std;
int l[155],r[155];
int n,m;
char a[155][155];
bool check(int x) {
for(int i = x;i <= n;i++) if(r[i]) return false;
return true;
}
int main() {
int ans = 0,y1,y = 1;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++) {
l[i] = m,r[i] = 0;
for(int j = 1;j <= m;j++) cin >> a[i][j];
for(int j = 1;j <= m;j++) if(a[i][j] == 'W') r[i] = j;
for(int j = m;j >= 1;j--) if(a[i][j] == 'W') l[i] = j;
}
for(int i = 1;i < n;i++) {
if(i & 1) {
y1 = max(max(y,r[i]),r[i + 1]);
ans += y1 - y;
y = y1;
}
else {
y1 = min(y,min(l[i],l[i + 1]));
ans += y - y1;
y = y1;
}
if(check(i + 1)) {
printf("%d\n",ans);
return 0;
}
ans++;
}
if(r[n]) {
if(n & 1) ans += r[n] - y;
else ans += y - l[n];
}
printf("%d\n",ans);
return 0;
}