题目链接:http://poj.org/problem?id=1679
题意:
给你一个图,问你这个图的最小生成树是否唯一。
题解:
求这个图的最小生成树和次小生成树。如果相等,则说明不唯一。
次小生成树(倍增算法):
maxn[k][i]:表示从节点i向上走2^k步,这一段中边权的最大值。
枚举每一条不在MST中的边,求出这条边两端点之间在MST上路径上的最大边权mx。
次小生成树(非严格) = max(MST - mx + len)
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <vector> 6 #define MAX_N 105 7 #define MAX_E 10005 8 #define MAX_K 20 9 #define INF 1000000000 10 11 using namespace std; 12 13 struct E 14 { 15 int s; 16 int t; 17 int len; 18 E(int _s,int _t,int _len) 19 { 20 s=_s; 21 t=_t; 22 len=_len; 23 } 24 E(){} 25 friend bool operator < (const E &a,const E &b) 26 { 27 return a.len<b.len; 28 } 29 }; 30 31 struct Edge 32 { 33 int dest; 34 int len; 35 Edge(int _dest,int _len) 36 { 37 dest=_dest; 38 len=_len; 39 } 40 Edge(){} 41 }; 42 43 int n,m,t; 44 int fa[MAX_N]; 45 int dep[MAX_N]; 46 int par[MAX_K][MAX_N]; 47 int maxn[MAX_K][MAX_N]; 48 bool vis[MAX_E]; 49 vector<E> e; 50 vector<Edge> edge[MAX_N]; 51 52 void read() 53 { 54 cin>>n>>m; 55 e.clear(); 56 for(int i=1;i<=n;i++) 57 { 58 edge[i].clear(); 59 } 60 int a,b,v; 61 for(int i=1;i<=m;i++) 62 { 63 cin>>a>>b>>v; 64 e.push_back(E(a,b,v)); 65 } 66 } 67 68 void init_union_find() 69 { 70 for(int i=1;i<=n;i++) 71 { 72 fa[i]=i; 73 } 74 } 75 76 int find(int x) 77 { 78 return fa[x]==x ? x : fa[x]=find(fa[x]); 79 } 80 81 void unite(int x,int y) 82 { 83 int px=find(x); 84 int py=find(y); 85 if(px==py) return; 86 fa[px]=py; 87 } 88 89 bool same(int x,int y) 90 { 91 return find(x)==find(y); 92 } 93 94 int kruskal() 95 { 96 init_union_find(); 97 sort(e.begin(),e.end()); 98 memset(vis,false,sizeof(vis)); 99 int cnt=0; 100 int res=0; 101 for(int i=0;i<e.size() && cnt<n-1;i++) 102 { 103 E temp=e[i]; 104 if(!same(temp.s,temp.t)) 105 { 106 cnt++; 107 res+=temp.len; 108 vis[i]=true; 109 unite(temp.s,temp.t); 110 edge[temp.s].push_back(Edge(temp.t,temp.len)); 111 edge[temp.t].push_back(Edge(temp.s,temp.len)); 112 } 113 } 114 return cnt==n-1 ? res : -1; 115 } 116 117 void dfs(int now,int p,int d,int l) 118 { 119 dep[now]=d; 120 par[0][now]=p; 121 maxn[0][now]=l; 122 for(int i=0;i<edge[now].size();i++) 123 { 124 Edge temp=edge[now][i]; 125 if(temp.dest!=p) dfs(temp.dest,now,d+1,temp.len); 126 } 127 } 128 129 void init_lca() 130 { 131 dfs(1,-1,0,-1); 132 for(int k=0;k+1<MAX_K;k++) 133 { 134 for(int i=1;i<=n;i++) 135 { 136 if(par[k][i]==-1) 137 { 138 par[k+1][i]=-1; 139 maxn[k+1][i]=-1; 140 } 141 else 142 { 143 par[k+1][i]=par[k][par[k][i]]; 144 maxn[k+1][i]=max(maxn[k][i],maxn[k][par[k][i]]); 145 } 146 } 147 } 148 } 149 150 int cal_max(int a,int b) 151 { 152 if(dep[a]>dep[b]) swap(a,b); 153 int res=-1; 154 for(int k=0;k<=MAX_K && dep[a]!=dep[b];k++) 155 { 156 if(((dep[b]-dep[a])>>k)&1) 157 { 158 res=max(res,maxn[k][b]); 159 b=par[k][b]; 160 } 161 } 162 if(a==b) return res; 163 for(int k=MAX_K-1;k>=0;k--) 164 { 165 if(par[k][a]!=par[k][b]) 166 { 167 res=max(res,maxn[k][a]); 168 res=max(res,maxn[k][b]); 169 a=par[k][a]; 170 b=par[k][b]; 171 } 172 } 173 return max(res,maxn[0][a]); 174 } 175 176 int sst(int mst) 177 { 178 if(mst==-1) return -1; 179 init_lca(); 180 int ans=INF; 181 for(int i=0;i<e.size();i++) 182 { 183 if(!vis[i]) 184 { 185 E temp=e[i]; 186 int mx=cal_max(temp.s,temp.t); 187 ans=min(ans,mst-mx+temp.len); 188 } 189 } 190 return ans==INF ? -1 : ans; 191 } 192 193 void work() 194 { 195 int mst=kruskal(); 196 if(mst==sst(mst)) cout<<"Not Unique!"<<endl; 197 else cout<<mst<<endl; 198 } 199 200 int main() 201 { 202 cin>>t; 203 while(t--) 204 { 205 read(); 206 work(); 207 } 208 }