http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10032
题目大意
这题目略长啊…简化题意是说给你一个n个点,m条边的无向图,每条边有边权。现在要你修改一些边的边权,使得前n-1条边是最小生成树,要求总的修改量最小,输出修改后每条边的边权。
解题报告
好题。从题意看是最小生成树相关的题目,其实这道题的正解是匹配。
设xi为每条边的边权,di为每条边的修改量。很容易想到要让前n-1条边成为最小生成树,那么必然是让前n-1条边权值改小,其它的边权值改大。即对于一条权值为x1,修改量为d1的树边 和一条权值为x2,修改量为d2的非树边,有: x1-d1<=x2+d2。将这个不等式变形,即 d1+d2>=x1-x2 右边是一个常数,要让左边尽量小,即左右相等的时候。观察这个式子,会发现它和我们做km时顶标和那个式子(lx[i]+ly[j]>=w[i][j])有些相似。因此,假如有一条非树边<i,j>,我们可以把从i到j的树边和这条非树边看作二分图的左右节点a,b,连一条权值为x[a]-x[b]的边。把图建出来再做一次km就可以了。
图论模型真心各种灵活,太考想象力了……
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<bitset> 5 using namespace std; 6 #define maxn 100 7 #define maxm 500 8 9 int n,m,w[maxm][maxm],g[maxn][maxn],lx[maxm],ly[maxm],l[maxm],a[maxm],b[maxm],z[maxm],slack[maxm]; 10 bitset <maxm> ux,uy; 11 12 bool find(int x) 13 { 14 ux[x]=1; 15 for (int i=1;i<=m;i++) 16 { 17 if (!uy[i]) 18 { 19 int t=lx[x]+ly[i]-w[x][i]; 20 if (t==0) 21 { 22 uy[i]=1; 23 if (!l[i] || find(l[i])) 24 { 25 l[i]=x; 26 return 1; 27 } 28 } 29 else if (slack[i]>t) slack[i]=t; 30 } 31 } 32 return 0; 33 } 34 void km() 35 { 36 memset(lx,-0x3f,sizeof(lx)); 37 memset(ly,0,sizeof(ly)); 38 memset(l,0,sizeof(l)); 39 for (int i=1;i<=m;i++) 40 for (int j=1;j<=m;j++) 41 if (w[i][j]>lx[i]) lx[i]=w[i][j]; 42 for (int j=1;j<=m;j++) 43 { 44 memset(slack,0x3f,sizeof(slack)); 45 while (1) 46 { 47 ux.reset(); 48 uy.reset(); 49 if (find(j)) break; 50 int d=0x3f3f3f3f; 51 for (int i=1;i<=m;i++) 52 if (!uy[i] && slack[i]<d) d=slack[i]; 53 for (int i=1;i<=m;i++) 54 if (ux[i]) lx[i]-=d; 55 for (int i=1;i<=m;i++) 56 { 57 if (uy[i]) ly[i]+=d; 58 else slack[i]-=d; 59 } 60 } 61 } 62 } 63 bool dfs(int pre,int u,int v,int id) 64 { 65 if (u==v) return 1; 66 for (int i=1;i<=n;i++) 67 { 68 if (i==pre || !g[u][i]) continue; 69 if (dfs(u,i,v,id)) 70 { 71 w[g[u][i]][id]=z[g[u][i]]-z[id]; 72 return 1; 73 } 74 } 75 return 0; 76 } 77 78 int main() 79 { 80 scanf("%d%d",&n,&m); 81 for (int i=1;i<=m;i++) 82 { 83 int x,y; 84 scanf("%d%d%d",&x,&y,&z[i]); 85 a[i]=x,b[i]=y; 86 } 87 for (int i=1;i<n;i++) g[a[i]][b[i]]=g[b[i]][a[i]]=i; 88 memset(w,0,sizeof(w)); 89 for (int i=n;i<=m;i++) 90 dfs(0,a[i],b[i],i); 91 km(); 92 for (int i=1;i<n;i++) printf("%d\n",z[i]-lx[i]); 93 for (int i=n;i<=m;i++) printf("%d\n",z[i]+ly[i]); 94 return 0; 95 }