【uva 10600】ACM Contest and Blackout(图论--次小生成树 模版题)
题意:有T组数据,N个点,M条边,每条边有一定的花费。问最小生成树和次小生成树的权值。
解法:具体请见 关于生成树的拓展 {附【转】最小瓶颈路与次小生成树}(图论--生成树)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 using namespace std; 7 8 const int N=105,M=5005,C=305; 9 int n,m,mm; 10 struct edge 11 { 12 int x,y,d,next; 13 edge() {} 14 edge(int i,int j,int k) {x=i;y=j;d=k;} 15 }e[M],ee[M]; 16 int fa[N],last[N],vis[N]; 17 int ve[M],f[N][N]; 18 19 bool cmp(edge x,edge y) {return x.d<y.d;} 20 int mmax(int x,int y) {return x>y?x:y;} 21 int mmin(int x,int y) {return x<y?x:y;} 22 23 int ffind(int x) 24 { 25 if (fa[x]!=x) fa[x]=ffind(fa[x]); 26 return fa[x]; 27 } 28 int MST() 29 { 30 int cnt=0,sum=0; 31 for (int i=1;i<=n;i++) fa[i]=i; 32 memset(ve,0,sizeof(ve)); 33 sort(e+1,e+1+m,cmp); 34 for (int i=1;i<=m;i++) 35 { 36 int fx=ffind(e[i].x),fy=ffind(e[i].y); 37 if (fx!=fy) 38 { 39 fa[fx]=fy,ve[i]=1; 40 ee[++cnt]=e[i],sum+=e[i].d; 41 if (cnt==n-1) break; 42 } 43 } 44 mm=cnt; 45 return sum; 46 } 47 void build() 48 { 49 memset(last,0,sizeof(last)); 50 for (int i=1;i<n;i++) 51 { 52 int x=ee[i].x,y=ee[i].y; 53 ee[i].next=last[x],last[x]=i; 54 ee[++mm]=edge(y,x,ee[i].d); 55 ee[mm].next=last[y],last[y]=mm; 56 } 57 } 58 void dfs(int x) 59 { 60 vis[x]=1; 61 for (int i=last[x];i;i=ee[i].next) 62 { 63 int y=ee[i].y; 64 if (vis[y]) continue; 65 for (int k=1;k<=n;k++) 66 if (vis[k]) f[k][y]=f[y][k]=mmax(f[k][x],ee[i].d);//要赋值2个f[][] 67 dfs(y); 68 } 69 } 70 int main() 71 { 72 int T; 73 scanf("%d",&T); 74 while (T--) 75 { 76 int x,y,d; 77 scanf("%d%d",&n,&m); 78 for (int i=1;i<=m;i++) 79 { 80 scanf("%d%d%d",&x,&y,&d); 81 e[i]=edge(x,y,d); 82 } 83 int mn=MST(),mmn=C*M; 84 build();//把最小生成树的边重新建树 85 memset(f,0,sizeof(f)); 86 memset(vis,0,sizeof(vis)); 87 dfs(1);//预处理f[x][y]:两点间路径的最大边权 88 for (int i=1;i<=m;i++) 89 { 90 if (ve[i]) continue; 91 mmn=mmin(mmn,mn-f[e[i].x][e[i].y]+e[i].d);//直接算出删除MST上的一条边时的MST,即次小生成树 92 } 93 printf("%d %d\n",mn,mmn); 94 } 95 return 0; 96 }