首页 > 其他分享 >最小生成树个数计算(简单版:同边权的边最多三条)

最小生成树个数计算(简单版:同边权的边最多三条)

时间:2024-06-08 22:31:42浏览次数:22  
标签:连通 2522% kruskal 个数 最小 生成 同边权 三条 两条

首先kruskal模版打一下(并查集维护连通块)

不熟悉kruskal可以前往:最小生成树(kruskal算法)-CSDN博客文章浏览阅读10w+次,点赞152次,收藏623次。一、概述最小生成树问题顾名思义,概括来说就是路修的最短。接下来引入几个一看就明白的定义:最小生成树相关概念:带权图:边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权。最小生成树(MST):权值最小的生成树。最小生成树的性质:假设G=(V,E)是一个连通网,U是顶点V的一个非空子集。若(u,v)是一条具有最小权值的边,其中u∈U,v∈..._kruskalhttps://blog.csdn.net/qq_41754350/article/details/81460643?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171785422516800178511966%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171785422516800178511966&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-81460643-null-null.142%5Ev100%5Epc_search_result_base6&utm_term=kruskal&spm=1018.2226.3001.4187接着要开始加东西了

按照相同边权的分成一组

我们需要三个计数变量:

cnt1是当前组有几条边可以用(在还没有使用任何本组的边时,有几条连接了不同的两个连通块)

cnt2是有几对不同的连通块被连接了(程序用set维护,自动去重,set的大小就是有几对不同的)

cnt3是最后需要用几条边来连通这几个连通块(当然是能少用就少用,由于边权相同,不用在乎到底用了哪几条,才会出现有多个最小生成树的状况)

接下来开始讨论不同的合并状况(乘法原理)

1.有三条边可用

需要一条边 选择一条 3种(不用担心选某一条会导致不满足连通,负责merge的循环保证了一条就能连通,也就是说只有两个不同的连通块,其他两条边也是连接这两个连通块的)

需要两条边:

        a.有三对连通块需要被连通(由于用两条边就行,肯定是下图情况) 三选二 3种

         b.有两对连通块要被连通  一条必连,另外两条二选一  2种

 

2.有两条边可以用

需要一条边 选择一下 2种

需要两条边 两条都用上 1种

只有一条边可以用就对个数没什么贡献了

具体的实现和细节就看代码啦(主要步骤前面都有提及)

提示:n是点数,m是边数,e存边,fa存并查集,ans存最小生成树边权和,cnt存最小生成树个数

#define mod 1000000007
int n,m,fa[40005];
struct edge{
	int a,b,c;
} e[100005];
long long ans,cnt=1;
bool cmp(edge x,edge y){ return x.c<y.c; }
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
int merge(int x,int y){
	x=find(x),y=find(y);
	if(x==y) return 0;
	fa[y]=x;
	return 1;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i){
		set<pair<int,int> > s; 
		pair<int,int> p;
		int j,cnt1=0,cnt3=0;
		for(j=i;j<=m&&e[i].c==e[j].c;j++){
			int x=find(e[j].a),y=find(e[j].b);
			if(x==y) continue;
			else{
				p.first=min(x,y),p.second=max(x,y);
				cnt1++;
				s.insert(p);
			}
		}
		for(i;i<j;i++) cnt3+=merge(e[i].a,e[i].b);
		ans+=e[i-1].c*cnt3;
		if(cnt1==2&&cnt3==1) cnt=cnt*2%mod;
		if(cnt1==3&&cnt3==1) cnt=cnt*3%mod;
		if(cnt1==3&&cnt3==2&&s.size()==3) cnt=cnt*3%mod;
		if(cnt1==3&&cnt3==2&&s.size()==2) cnt=cnt*2%mod;
	}
	printf("%lld %lld\n",ans,cnt);
	return 0;
}

标签:连通,2522%,kruskal,个数,最小,生成,同边权,三条,两条
From: https://blog.csdn.net/2401_84512298/article/details/139551654

相关文章