题解:AT_abc352_e [ABC352E] Clique Connect

思路

考虑第一问(连通性),显然要使用并查集(下文的代码中使用了 bfs)。

但是我们显然不能将所有边都建出来。

因为只考虑连通性,所以只需保证一个集合内所选的边能保证所有点之间互相连通即可。

再考虑第二问(最小生成树)。

注意:下文中的 nn 与原题中的 NN 不是同一个意义,集合即顶点子集。

肯定不能建完图,但是我们知道,连接 nn 个点并使其互相连通至少需要 n1n-1 条边。因为一个集合内的边都是等价的,所以只需任意选择 n1n-1 条即可。

正确性证明:

在我们进行 kruskal 时,我们是先对边长进行排序,然后判断两个端点是否连通。

现在在一个集合中,每一条边边长都一样,那么它们一定会排在一起。

现在我们选择了 n1n-1 条边,那么这个集合内的点已经保证连通了,就没有必要再选了,剩下的边都是浪费。

为了不浪费我们的时间资源和空间资源,我们只需任意选择 n1n-1 条边即可。

代码实现

  • 因为如果第一问使用并查集维护本题要写 22 个并查集,所以我第一问使用了 bfs 的方法判断连通。
  • 因为要判断图的连通,所以只应进行 11 次 bfs。
  • union 在 C++ 中为关键字,所以并查集的合并操作我使用了 vnion
  • 本题数据范围可能爆 int

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k[400005],c[400005],a[400005],vis[400005],fa[400005];
queue<int>q;
struct node{
	int u,v,w,nxt;
}e[800005];
int head[400005],cnt;
void bfs(int now){
	q.push(now);
	while(!q.empty()){
		int v=q.front();q.pop();
		if(vis[v])continue; 
		vis[v]=1;
		for(int i=head[v];i;i=e[i].nxt){
			q.push(e[i].v);
		}
	}
}
bool cmp(node _,node __){
	if(_.w<__.w)return 1;
	return 0;
}
int findd(int now){
	if(fa[now]==now)return now;
	return fa[now]=findd(fa[now]);
}
void vnion(int _,int __){
	fa[findd(__)]=findd(_);
}
void add(int u,int v,int w){
	e[++cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
int tot=0;
signed main(){
	cin>>n>>m;
	for(int i=1;i<=400004;i++)fa[i]=i;
	for(int i=1;i<=m;i++){
		cin>>k[i]>>c[i];
		for(int j=1;j<=k[i];j++){
			cin>>a[j];
		} 
		for(int j=2;j<=k[i];j++){
			add(a[1],a[j],c[i]);
			add(a[j],a[1],c[i]);
		}
	}
	bfs(1);
	for(int i=1;i<=n;i++){
		if(vis[i]==0){
			cout<<-1;
			return 0;
		}
	}
	sort(e+1,e+cnt+1,cmp);
	long long ans=0;
	for(int i=1;i<=cnt;i++){
		if(findd(e[i].u)!=findd(e[i].v)){
			vnion(e[i].u,e[i].v);
			ans+=e[i].w;
			tot++;
		}
		if(tot==n-1)break;
	}
	cout<<ans;
	return 0;
}
posted @   Weslie_qwq  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示