题目链接
题目大意
给出一个n个点m条边的图,每个边有权值w,你可以删除一些边,使得剩下的边的最小生成树大小不变并且这个图的最小生成树是独一无二的。现在我们想要知道删除的边的权值和最小是多少?
题目思路
要形成独一无二的最小生成树,那么就没有别的边可以在构造最小生成树时加入最小生成树。我们可以在计算最小生成树时求所有可以加入最小生成树的边权和,再减去一个最小生成树的边权和就是答案。
其实真的不难理解,但是不知道为什么没写出来,要理解kruskal的本质直接一下a
代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,fa[maxn];
ll ans;
struct node{
int u,v,w;
}e[maxn];
bool cmp(node a,node b){
return a.w<b.w;
}
int findd(int x){
if(x==fa[x])
return x;
return fa[x]=findd(fa[x]);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){//并查集初始化
fa[i]=i;
}
for(int i=1;i<=m;i++){
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+1+m,cmp);
for(int l=1,r=1;l<=m;l=r){//注意直接l=r为下一个条件
while(r<=m&&e[l].w==e[r].w){
r++;
}
for(int i=l;i<r;i++){//表示l到r-1得边权值都相等
if(findd(e[i].v)!=findd(e[i].u)){
ans+=e[i].w;//找总边权值
}
}
for(int i=l;i<r;i++){//找最小生成树得边权值
if(findd(e[i].v)!=findd(e[i].u)){
ans-=e[i].w;
fa[findd(e[i].v)]=findd(e[i].u);
}
}
}
printf("%lld",ans);
return 0;
}