「ARC112D」 Skate

题意

一个长 \(h\)\(w\) 的地图,# 代表陆地,. 代表冰面,如果人在陆地上可以向任何方向转向,否则只能一直滑到边缘然后在边缘选择转向。

现在可以花费 \(1\) 的代价把一块冰面改为陆地,求最少花费多少代价使得人从任何地方出发都可以滑到所有地方。

分析

显然只会选择垂直转向,因为掉头和停下来再向前没有意义。

这是个点的联通问题,发现加入一块陆地就可以把这个点所在横线和竖线上的点全部联通。

转化为用最少的点让所有线联通在一起。

联通类问题的一个好用工具就是并查集,用 \(2n\) 个数表示横线和竖线,这个思路好像在二分图的一些题里也用过。

输入时如果有一块陆地,就直接把它的横与竖连接起来。

枚举每一条横线和竖线,给它们的 \(pre\) 打一个 bool 标记。每枚举到一条线,如果它父亲没有被标记过,就说明它是一个新的连通块,这就需要用一条边把它和之前的块连在一起,所以给答案加一。

最后在横与竖的答案中取最小值,由于第一个块不需要连接,所以给答案减一。

注意因为有边界,所以最开始要把四个顶点的横竖线连起来。

Code

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
// static char buf[100],*p1=buf,*p2=buf,obuf[100],*p3=obuf;
// #define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++
// #define putchar(x) (p3-obuf<100)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
mt19937_64 rnd(chrono::system_clock::now().time_since_epoch().count());
#define dbg(x) cout<<#x<<": "<<x<<"\n"
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
inline void write(ll x){if(!x){putchar(48);putchar('\n');return;}short top=0,s[40];if(x<0)x=-x,putchar(45);while(x)s[top++]=x%10^48,x/=10;while(top--)putchar(s[top]);putchar('\n');}
namespace tobe{
	const ll maxn=2e5+5,mod=998244353;
	ll n,m,pre[maxn];
	bool vis[maxn];
	string s;
	inline ll find(ll x){return x==pre[x]?x:pre[x]=find(pre[x]);}
	inline void merge(ll x,ll y){
		x=find(x),y=find(y);
		if(x==y)return;
		pre[x]=y;
	}
	inline void mian(){
		n=read(),m=read();
		for(ll i=1;i<=n+m;++i)pre[i]=i;
		for(ll i=1;i<=n;++i){
			cin>>s;s=" "+s;
			for(ll j=1;j<=m;++j){
				if(s[j]=='#')merge(i,j+n);
			}
		}
		merge(1,1+n),merge(n,1+n);
		merge(1,n+m),merge(n,n+m);
		ll ans1=0,ans2=0;
		for(ll i=1;i<=n;++i){
			if(!vis[find(i)]){
				vis[find(i)]=1;
				++ans1;
			}
		}
		memset(vis,0,sizeof(vis));
		for(ll i=n+1;i<=n+m;++i){
			if(!vis[find(i)]){
				vis[find(i)]=1;
				++ans2;
			}
		}
		write(min(ans1,ans2)-1);
	}
}
signed main(){
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ll t=1;
	while(t--)tobe::mian();
	// fwrite(obuf,p3-obuf,1,stdout);
	return 0;
}
posted @ 2024-12-20 15:34  run-away  阅读(10)  评论(0)    收藏  举报