Codeforces 1108F MST Unification(最小生成树性质)
题目链接:MST Unification
题意:给定一张连通的无向带权图。存在给边权加一的操作,求最少操作数,使得最小生成树唯一。
题解:最小生成树在算法导论中有这个性质:
把一个连通无向图的生成树边按权值递增排序,称排好序的边权列表为有序边权列表,则任意两棵最小生成树的有序边权列表是相同的。(算法导论23.1-8)
通过这个性质,考虑边权相同的边,把这些边中能够替代的边计算出来即可。
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <deque> 5 #include <stack> 6 #include <cmath> 7 #include <cstdio> 8 #include <vector> 9 #include <string> 10 #include <cstring> 11 #include <fstream> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 #define eps 1e-8 17 #define pb push_back 18 #define PI acos(-1.0) 19 #define INF 0x3f3f3f3f 20 #define clr(a,b) memset(a,b,sizeof(a) 21 #define bugc(_) cerr << (#_) << " = " << (_) << endl 22 #define FAST_IO ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL) 23 24 typedef long long ll; 25 typedef unsigned long long ull; 26 const int N=2e5+10; 27 28 int fa[N]; 29 struct edge{ 30 int u,v,w; 31 }e[N]; 32 33 int fi(int x){ 34 return fa[x]==x?x:fa[x]=fi(fa[x]); 35 } 36 37 bool cmp(edge x,edge y){ 38 return x.w<y.w; 39 } 40 41 int main(){ 42 int n,m,ans=0; 43 scanf("%d%d",&n,&m); 44 for(int i=1;i<=n;i++) fa[i]=i; 45 for(int i=1;i<=m;i++){ 46 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 47 } 48 sort(e+1,e+1+m,cmp); 49 for(int i=1;i<=m;){ 50 int j=i; 51 while(e[j].w==e[i].w) j++; 52 for(int k=i;k<j;k++){ 53 int fx=fi(e[k].u),fy=fi(e[k].v); 54 if(fx!=fy) ans++; 55 } 56 for(int k=i;k<j;k++){ 57 int fx=fi(e[k].u),fy=fi(e[k].v); 58 if(fx!=fy){ 59 fa[fx]=fy; 60 ans--; 61 } 62 } 63 i=j; 64 } 65 printf("%d\n",ans); 66 return 0; 67 }