0%

2060.奶牛选美

2060. 奶牛选美

题目描述:

听说最近两斑点的奶牛最受欢迎,约翰立即购进了一批两斑点牛。

不幸的是,时尚潮流往往变化很快,当前最受欢迎的牛变成了一斑点牛。

约翰希望通过给每头奶牛涂色,使得它们身上的两个斑点能够合为一个斑点,让它们能够更加时尚。

牛皮可用一个 $ N \times M $ 的字符矩阵来表示,如下所示:

1
2
3
4
5
6
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....

其中, $ X $ 表示斑点部分。

如果两个 $ X $ 在垂直或水平方向上相邻(对角相邻不算在内),则它们属于同一个斑点,由此看出上图中恰好有两个斑点。

约翰牛群里所有的牛都有两个斑点

约翰希望通过使用油漆给奶牛尽可能少的区域内涂色,将两个斑点合为一个。

在上面的例子中,他只需要给三个 .. 区域内涂色即可(新涂色区域用 ∗∗ 表示):

1
2
3
4
5
6
................
..XXXX....XXX...
...XXXX*...XX...
.XXXX..**..XXX..
........XXXXX...
.........XXX....

请帮助约翰确定,为了使两个斑点合为一个,他需要涂色区域的最少数量。

输入格式

第一行包含两个整数 $ N $ 和 $ M $ 。

接下来 $ N $ 行,每行包含一个长度为 $ M $ 的由 $ X $ 和 .. 构成的字符串,用来表示描述牛皮图案的字符矩阵。

输出格式

输出需要涂色区域的最少数量。

数据范围

$ 1\le N, M \le 50 $

输入样例:

1
2
3
4
5
6
7
6 16
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....

输出样例:

1
3

题解:

因为数据范围比较小,所以可以将每块连通块中 $ X $ 的坐标记下来,然后直接暴力枚举求得最短距离。

(bfs 的时候,注意队列里面是没有重复的,每个元素只进一次队列,所以每次加入后就要打上标记)

代码:

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
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 1e2 + 10;
const int maxm = 1e2 + 10;
int t, n, m, k;
char g[maxn][maxn];
vector<pair<int, int>> a, b;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
void bfs(int x, int y, int flag)
{
queue<pair<int, int>> q;
q.push({x, y});
g[x][y] = '.';
while (!q.empty())
{
auto out = q.front();
q.pop();
if (flag)
{
b.push_back(out);
}
else
{
a.push_back(out);
}
for (int i = 0; i < 4; i++)
{
int newx = dx[i] + out.first;
int newy = dy[i] + out.second;
if (newx < 0 || newx >= n || newy < 0 || newy >= m || g[newx][newy] == '.')
continue;
q.push({newx, newy});
g[newx][newy] = '.';
}
}
}
int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
read(n, m);
for (int i = 0; i < n; i++)
{
scanf("%s", g[i]);
}
int cnt = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == 'X')
{
if (cnt)
{
bfs(i, j, cnt);
}
else
{
bfs(i, j, cnt);
}
cnt++;
}
}
}
int ans = INF;
for (auto x : a)
{
for (auto y : b)
{
ans = min(ans, abs(x.first - y.first) + abs(x.second - y.second) - 1);
}
}
cout << ans << endl;
return 0;
}