题目链接:https://codeforces.com/contest/1108/problem/F
题意是给了n个点m条边,让构成一个最小生成树,但是这个最小生成树不唯一(存在权值相同的不同方案),可以对边进行操作,使任意一条边权值+1,问最小要操作几次才能使最小生成树唯一。
思路就是如果最小生成树不唯一,那么图中肯定存在了多条权值相同的边,那么对于权值相同的边来说,如果选了某些边可能会引起冲突,为了避免冲突我们首先先找出权值相同且可以选的边,然后再依次进行加边,如果出现了冲突,那么这条边的权值+1就好了。代码实现的思路是先将所有权值相同的边的个数统计出来,然后依次加边,如果存在了两条边在同一个集合里就不要这个边让cnt--,最终下来的cnt就是会有冲突的边,让他们权值+1就好了。
AC代码:
#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
struct Node{
int x, y, w;
bool operator < (const Node &a) const{
return a.w > w;
}
}Edge[maxn];
int pre[maxn];
int n,m;
void init(){
for(int i=0;i<=n;i++) pre[i] = i;
}
int Find(int x){
if(x != pre[x]) pre[x] = Find(pre[x]);
return pre[x];
}
int main()
{
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
scanf("%d%d%d",&Edge[i].x, &Edge[i].y, &Edge[i].w);
}
sort(Edge, Edge + m);
int ans = 0;
for(int i=0;i<m; ){
int j = i;
int cnt = 0;
while(Edge[i].w == Edge[j].w) j ++;
for(int k=i;k<j;k++){
int fx = Find(Edge[k].x);
int fy = Find(Edge[k].y);
if(fx != fy) cnt ++;
}
for(int k=i;k<j;k++){
int fx = Find(Edge[k].x);
int fy = Find(Edge[k].y);
if(fx != fy) pre[fy] = pre[fx], cnt --;
}
ans += cnt;
i = j;
}
printf("%d\n", ans);
return 0;
}