题目链接: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;
}