最小生成树的唯一性

kruskal,第一遍保存重复权值的边,然后把每一条保存的删掉一次做kruskal,这道题代码有好几个亮点重点降低复杂度,首先是路径压缩新方法,再是qsort对结构体排序;

答案:

#include<stdio.h>
#include<stdlib.h>
#define inf 9999//kruskal,第一遍保存收集的边,然后把每一条保存的删掉一次kruskal
//若删掉了原树的一条还可以有同样权值的树就说明不唯一
//但是每条都试试会超时
//其实只有相同权重的边有可能,因为一颗最小生成树边一定是nv-1,且从小到大收
//所以只col中收集重复权重的边 (注意如果e1和e2重复,则两条都要收集)
typedef struct et{
	int v1,v2;
	int val;
}et;
et e[130000]; //这里边数很大,99999不够 
int nv,ne,par[99999],col[130000],cnt,weight,cs;
/*int Find(int a){
    int i;
	for(i=a;par[i]!=i;i=par[i]);
	par[a]=i;//顺便路径压缩以下 
	return i;
}*///这种路径压缩还是不够,还是超时换下面这种,很重要 
int Find(int a){
	return a==par[a]?a:(par[a]=Find(par[a]));
}
int cmp(const void* a,const void* b){
	return (*(const struct et*)a).val-(*(const struct et*)b).val;
	//注意.优先级高,解引用前要加一个括号 
}
int main(){
	et p;
	int msts=0,i,j,count=0,w2;
	scanf("%d%d",&nv,&ne);
	for(i=0;i<ne;i++){
		scanf("%d%d%d",&e[i].v1,&e[i].v2,&e[i].val);
	}
	for(i=1;i<=nv;i++){
		par[i]=i;
	}
/*	for(i=0;i<ne;i++){
		for(j=0;j<ne-i-1;j++){
			if(e[j].val>e[j+1].val){
				p=e[j];
				e[j]=e[j+1];
				e[j+1]=p;
			}
		}
	}*///冒泡排序时间复杂度太高 
	qsort(e,ne,sizeof(et),cmp);
	for(i=0;i<ne;i++){
		if(Find(e[i].v1)!=Find(e[i].v2)){//不成环 
//			par[e[i].v1]=Find(e[i].v2); 
            par[Find(e[i].v1)]=Find(e[i].v2);
		//这里很重要,应该让v1所在根的par等于v2所在根!
			msts++;
			weight+=e[i].val;
			if(i<nv-1&&e[i].val==e[i+1].val||i&&e[i].val==e[i-1].val) col[cs++]=i;
//			printf("%dkk ",i);
			if(cs==nv-1) break;
		}
	}
//	printf("\n");
	for(i=1;i<=nv;i++){
		if(Find(i)==i) count++;
	}
	if(count!=1) printf("No MST\n%d",count);
	else if(cs==0) printf("%d\nYes",weight); 
	else{
		printf("%d\n",weight);
		int f=0;
		for(j=0;j<cs;j++){
			w2=0;
			cnt=0;
			for(i=1;i<=nv;i++){
		        par[i]=i;
	        }
	        for(i=0;i<ne;i++){
	        	if(i==col[j]) continue;//每条边都舍弃试试 
		        if(Find(e[i].v1)!=Find(e[i].v2)){//不成环 
			        par[Find(e[i].v1)]=Find(e[i].v2);
		    	    cnt++;
			        w2+=e[i].val;
			        if(cnt==nv-1) break;
//			        printf("%d %dpp ",i,w2);
		        }
	        }
	        if(w2==weight&&cnt==nv-1){
	        	f=1;
	        	break;
			}
		} 
		if(f) printf("No");
		else printf("Yes");
	}
	return 0;
} 

路径压缩改良:

/*int Find(int a){
    int i;
	for(i=a;par[i]!=i;i=par[i]);
	par[a]=i;//顺便路径压缩以下 
	return i;
}*///这种路径压缩还是不够,还是超时换下面这种,很重要 
int Find(int a){
	return a==par[a]?a:(par[a]=Find(par[a]));
}

qsort对结构体排序替代冒泡排序:

/*	for(i=0;i<ne;i++){
		for(j=0;j<ne-i-1;j++){
			if(e[j].val>e[j+1].val){
				p=e[j];
				e[j]=e[j+1];
				e[j+1]=p;
			}
		}
	}*///冒泡排序时间复杂度太高 
int cmp(const void* a,const void* b){
	return (*(const struct et*)a).val-(*(const struct et*)b).val;
	//注意.优先级高,解引用前要加一个括号 
}
qsort(e,ne,sizeof(et),cmp);

题目:

给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一。本题就要求你计算最小生成树的总权重,并且判断其是否唯一。

输入格式:

首先第一行给出两个整数:无向图中顶点数 N(≤500)和边数 M。随后 M 行,每行给出一条边的两个端点和权重,格式为“顶点1 顶点2 权重”,其中顶点从 1 到N 编号,权重为正整数。题目保证最小生成树的总权重不会超过 230。

输出格式:

如果存在最小生成树,首先在第一行输出其总权重,第二行输出“Yes”,如果此树唯一,否则输出“No”。如果树不存在,则首先在第一行输出“No MST”,第二行输出图的连通集个数。

输入样例 1:

5 7
1 2 6
5 1 1
2 3 4
3 4 3
4 1 7
2 4 2
4 5 5

输出样例 1:

11
Yes

输入样例 2:

4 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3

输出样例 2:

4
No

输入样例 3:

5 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3

输出样例 3:

No MST
2
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值