AtCoder Regular Contest 112 D 并查集dsu

AtCoder Regular Contest 112 D

Solution

官方题解

原题链接

不难发现,对于所有的格子,只要它是一个有效格子,那么它们就可以到达 ( 1 , 1 ) (1,1) (1,1) 这个格子。因此我们可以反过来看这个问题,如果所有从 ( 1 , 1 ) (1,1) (1,1) 出发的旅行者都能到达所有格子,那么这张图就是一个有效图。

因为有墙面的存在,我们有以下结论

  • 1 − s t 1-st 1st 行是有效的 ⟺ 1 − s t 1-st 1st 列是有效的
  • 1 − s t 1-st 1st 行是有效的 ⟺ W − t h W-th Wth 列是有效的
  • H − t h H-th Hth 行是有效的 ⟺ 1 − s t 1-st 1st 列是有效的
  • H − t h H-th Hth 行是有效的 ⟺ W − t h W-th Wth 列是有效的
  • 1 − s t 1-st 1st 行是有效的

此外,如果 ( r , c ) (r,c) (r,c) 这个点是地面,我们可以得到

  • r r r t h th th 行和 c c c t h th th 列都是有效的

把这个点和井号的集合想成一个图,假如有一行是可行的,那么它对于的列也是可行的。 即,如果所有行均可行,则连接与该行相对应的所有顶点。 因此,使所有行均可行所需的最小更改数等于使所有顶点对应于这些行所需的最小边数。 通过从包含与行相对应的顶点的已连接部分的数量中减去1,可以找到此最小边数。 我们也可以类似地处理这些列。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
#define debug(a) cout << #a << " " << a << endl
const int maxn = 1e5 + 7;
const int N = 1500, M = N * 2;
const int inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;

char g[N][N];
int p[maxn], t1[maxn], t2[maxn];

int find(int x) { //返回x的祖宗节点 + 路径压缩
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}

void unionfind(int x, int y) {
	p[find(x)] = find(y);
}
int main() {

//	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

//	ios::sync_with_stdio(false);
	int H, W;
	cin >> H >> W;

	for(int i = 1; i <= H + W; i++) p[i] = i;

	for(int i = 1; i <= H; i++)
		for(int j = 1; j <= W; j++) {
			cin >> g[i][j];
			if(g[i][j] == '#') unionfind(i, j + H);
		}


	unionfind(1, H + 1);//通过添加一个偏移量保证行列的不同
	unionfind(1, H + W);
	unionfind(H, H + 1);
	unionfind(H, H + W);


	int ans1 = 0, ans2 = 0;
	for(int i = 1; i <= H; i++) t1[find(i)] = 1;
	for(int i = H + 1; i <= H + W; i++) t2[find(i)] = 1;
	for(int i = 1; i <= H + W; i++) ans1 += t1[i];
	for(int i = 1; i <= H + W; i++) ans2 += t2[i];

	cout << min(ans1, ans2) - 1;





	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值