题意
给一个无向加权联通图,没有重边和环。在这个图中可能存在多个最小生成树(MST),你可以进行以下操作:选择某条边使其权值加一,使得MST权值不变且唯一。求最少的操作次数。
分系:首先我们先要知道为什么会出现多个最小生成树的情况? 因为有些边的权值是相同的 , 所以在构造最小生成树的时候 ,我们是可以选择不同的边 , 构造出不同的最小生成树;
如果我们要是生成的最小生成树是唯一的 , 那我们每一次的加边十都只能是一种选择
也就是说,在构造过程的某一次抉择中,如果有多条边,他们的权值均最小,且合法(不会构成环,可以加入MST),而且冲突【二者只能选其一,即选择其中一条后,另一条再加进去就会构成环】,那么我们只选择一条加入MST,剩下的冲突边,都权值加一,那么他们就不能再被选到MST里面了。
为什么必须强调是冲突边?因为如果不冲突,我们可以先选择一条边权最小的(为w)的边e1加入,下次再选择时,边权最小还是为w,但是现在是边e2了,此时e2由于不会构成环,还是可以加入到MST中。所以实际上它们两个是在同一个方案里的,不够成多种选择。
很明显,上面的构造过程是采用了 kruskal算法(即避圈法),我们只需要在构造过程中,统计冲突边的数量,累加起来即可。
---------------------
原文:https://blog.csdn.net/Floraqiu/article/details/86630053
#include<bits/stdc++.h> using namespace std ; const int maxn = 2e5+10; int n,m,fa[maxn]; struct no{ int u,v,w; }e[maxn]; bool cmp(no a , no b) { return a.w<b.w; } void init(){ for(int i=1 ; i<=n ; i++) fa[i]=i; } int Find(int x) { return x==fa[x] ? x:fa[x]=Find(fa[x]); } void Merge(int x, int y) { int fx = Find(x), fy = Find(y); if(fx != fy) fa[x] = fy; } int main() { while(~scanf("%d%d",&n,&m)) { init(); for(int i=0 ; i<m ; i++) scanf("%d%d%d",&e[i].u , &e[i].v , &e[i].w); sort(e , e+m , cmp); int ans=0; for(int i=0 ; i<m ; ) { int num=0; int j=i; while(e[i].w ==e[j].w) ///找到权值相同的尾部坐标 j++; for(int k=i ; k<j ; k++) ///i到j都是边权最小而且都是相同的边 { int fx = Find(e[k].u) , fy=Find(e[k].v); if(fx!=fy)///统计可以选择的合法边的数量 num++; } ///注意,我们还得判断合法边里的冲突边 ,才是我们想要的答案 for(int k=i ; k<j ; k++) { int fx=Find(e[k].u) , fy=Find(e[k].v); if(fx!=fy)///从合法边中减去非冲突边(即可以被选入到同一个方案里,不互相冲突的边) Merge(fx,fy) , num--; } i=j; ans+=num; } printf("%d ",ans); } return 0; }