arc112d
大意
略...
思路
乱搞,很难证明(
显然,任意一个点都可以到达四周,或者说左下角那一个点。
所以,只要能从左下角那一个点,到达其他所有的点,那么就满足题意了。
我们将行和列抽象为两个互不相关的并查集。
如果两个 '#' 在同一行,我们就将它们对应的列并查集链接,
如果在同一列,就将行并查集链接。
含义为,两列(行) 的点可以互相到达。
注意,首列和尾列,首行和尾行开始就应该链接。
如果某个 '#' 在第1行或者第h行,那么我们要将其对应的列和首列链接,想一下图就能发现。
如果某个 '#' 在第1列或者第w列,那么我们要将其对应的行和首行链接。
如果每行间都能互相到达,或者每列间都能互相到达,那么就是满足题意的。
所以,记 (c_1) 为行并查集独立集个数, (c_2) 为列并查集独立集个数。
答案为 (min(c_1, c_2) -1)
(因为,添加一个 '#' 只能将两个独立集合并)
代码
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)
const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
int h, w;
int bcj[2][1010];
int row[1001], col[1001];
int fd(cint x, bool st) {
return bcj[st][x] == x ? x : bcj[st][x] = fd(bcj[st][x], st);
}
int main() {
ios::sync_with_stdio(false);
int s = -1, ss = -1;
cin >> h >> w;
char a;
for(int i=1; i<=h; i++) bcj[0][i] = i;
for(int i=1; i<=w; i++) bcj[1][i] = i;
bcj[1][w] = 1; bcj[0][h] = 1;
for(int i=1; i<=h; i++)
for(int j=1; j<=w; j++) {
cin >> a;
if(a == '#') {
if(i == 1 || i == h) bcj[1][fd(bcj[1][j], 1)] = fd(bcj[1][1], 1);
else {
if(row[i] != 0) bcj[1][fd(bcj[1][j], 1)] = fd(bcj[1][row[i]], 1);
row[i] = j;
}
if(j == 1 || j == w) bcj[0][fd(bcj[0][i], 0)] = fd(bcj[0][1], 0);
else {
if(col[j] != 0) bcj[0][fd(bcj[0][i], 0)] = fd(bcj[0][col[j]], 0);
col[j] = i;
}
}
}
int tmp = 0;
for(int i=1; i<=w; i++)
if(bcj[1][i] == i) ++tmp;
int tmp1 = 0;
for(int i=1; i<=h; i++)
if(bcj[0][i] == i) ++tmp1;
cout << min(tmp1, tmp) - 1 << endl;
return 0;
}