题意:给个2×N的矩阵,'.'表示可以站守卫,‘X'表示墙,守卫可以查看上下左右4个方向,问至少放多少守卫,
视线可以覆盖所有’.'位置。
思路:如果N×N的话,可以用二分图,这个才2,不用那样。
如果是两行连续的
....
..
不论是否等长,都需要至少2个守卫才能全部覆盖。
如果是
X.X
. . .
这种两个墙之间有且只有一个空位,如果对面有空位那就在对面放守卫,因为对面放守卫,遇到上面这种情况,
不仅可以覆盖当前位置还可以覆盖下一行的一段,除非对面没位置,才在当前位置放守卫。
即使遇到下面这种情况
X.X
X.X
上面的理论也是成立的。
当把这种仅有一个的空缺填满了,剩下的就是第一种情况,两行不等长的连续,或者仅有一行连续。这种都是
一行一个守卫。
这样分情况做就可以了。
<pre name="code" class="cpp">#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
char mp[2][N];
bool flag[2][N];
void run()
{
int n, ans = 0;
scanf("%d", &n);
scanf("%s", mp[0]);
scanf("%s", mp[1]);
memset(flag, 0, sizeof(flag));
//下面的二重循环是为了填补X.X的情况
for (int i = 0; i < n; i++)
for (int bt = 0; bt < 2; bt++)
if (mp[bt][i] == '.' && !flag[bt][i])
{
if (i - 1 < 0 || mp[bt][i-1] == 'X')
if (i + 1 >= n || mp[bt][i+1] == 'X')
{
if (mp[bt^1][i] == '.')
{
for (int j = 1; j <= n; j++)
if (i + j < n && mp[bt^1][i+j] == '.')//向右填充覆盖区域
flag[bt^1][i+j] = 1;
else
break;
for (int j = 1; j <= n; j++)
if (i - j >= 0 && mp[bt^1][i - j] == '.')//向左填充覆盖区域
flag[bt^1][i-j] = 1;
else
break;
}
ans++;
flag[bt^1][i] = flag[bt][i] = 1;
}
}
// 填充连续行
for (int i = 0; i < 2; i++)
for (int j = 0; j < n; j++)
if (mp[i][j] == '.' && !flag[i][j])
{
ans++;
for (int k = j; k < n; k++)
if (mp[i][k] == 'X')
break;
else
flag[i][k] = 1;
if (mp[i^1][j] == '.' && !flag[i^1][j])
{
flag[i^1][j] = 1;
}
}
printf("%d\n", ans);
}
int main()
{
int T, cas = 1;
scanf("%d", &T);
while (T--)
{
printf("Case #%d: ", cas++);
run();
}
return 0;
}