今天刚学了并查集,也发了一篇博客,想着趁热打铁练一题,于是在计蒜客上找了一道并查集的题。
题目链接
要是不知道这道题是并查子集模板题,我应该会把它当成搜索来写
不过都知道是并查子集了,那就简单了。这题目很显然同行
或同列
有集合关系
(找亲戚or找朋友or修路?) 。那么,我们可以先把每一行或每一列的炸弹都建立亲戚关系。然后就是简单的并查集,求最少连通路的问题了
之前唯二写的两个并查子集都是一维的,既然题目是二维的,我就想先把二维数组转化为一维数组,总所周知,[n][m]
的地图可表示为[n* m]
,显然,相应的第i
行第j
列可表示为[i* m+j]
,那问题就简单了。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long
char p[1005][1005];
int pre[1000005];
int tong[1000005];
int find(int x)
{
int r = x;
while (r != pre[r])
r = pre[r];
int temp, k = x;
while (pre[k] != r)
{
temp = pre[k];
pre[k] = r;
k = temp;
}
return r;
}
void mix(int a, int b)
{
int fa = find(a);
int fb = find(b);
if (fa != fb)
pre[fa] = fb;
}
int main()
{
int n, m,a;
cin >> n >> m;
for (int i = 1; i <= n * m + 5; i++)
pre[i] = i;
for (int i = 1; i <= n; i++)
scanf("%s", p[i] + 1);
for (int i = 1; i <= n; i++)//给每行的1都建立关系
{
int flag = 0;
for (int j = 1; j <= m; j++)
{
if (p[i][j] == '1' && flag == 0)
{
a = (i - 1) * m + j;
flag = 1;
}
else if (p[i][j] == '1' && flag == 1)
mix(a, (i - 1) * m + j);
}
}
for (int j = 1; j <= m; j++)//给每列的1都建立关系
{
int flag = 0;
for (int i = 1; i <= n; i++)
{
if (p[i][j] == '1' && flag == 0)
{
a = (i - 1) * m + j;
flag = 1;
}
else if (p[i][j] == '1' && flag == 1)
mix(a, (i - 1) * m + j);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (p[i][j] == '1')
tong[find((i - 1) * m + j)] = 1;
for (int i = 1; i <= n * m; i++)
if (tong[i])
ans++;
cout << ans << endl;
return 0;
}