您的位置:首页 > 其它

SGU 206 Roads

2013-03-31 11:03 183 查看
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就可以了。

图论模型真心各种灵活,太考想象力了……

代码

View Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<bitset>
using namespace std;
#define maxn 100
#define maxm 500

int n,m,w[maxm][maxm],g[maxn][maxn],lx[maxm],ly[maxm],l[maxm],a[maxm],b[maxm],z[maxm],slack[maxm];
bitset <maxm> ux,uy;

bool find(int x)
{
ux[x]=1;
for (int i=1;i<=m;i++)
{
if (!uy[i])
{
int t=lx[x]+ly[i]-w[x][i];
if (t==0)
{
uy[i]=1;
if (!l[i] || find(l[i]))
{
l[i]=x;
return 1;
}
}
else if (slack[i]>t) slack[i]=t;
}
}
return 0;
}
void km()
{
memset(lx,-0x3f,sizeof(lx));
memset(ly,0,sizeof(ly));
memset(l,0,sizeof(l));
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
if (w[i][j]>lx[i]) lx[i]=w[i][j];
for (int j=1;j<=m;j++)
{
memset(slack,0x3f,sizeof(slack));
while (1)
{
ux.reset();
uy.reset();
if (find(j)) break;
int d=0x3f3f3f3f;
for (int i=1;i<=m;i++)
if (!uy[i] && slack[i]<d) d=slack[i];
for (int i=1;i<=m;i++)
if (ux[i]) lx[i]-=d;
for (int i=1;i<=m;i++)
{
if (uy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
}
}
bool dfs(int pre,int u,int v,int id)
{
if (u==v) return 1;
for (int i=1;i<=n;i++)
{
if (i==pre || !g[u][i]) continue;
if (dfs(u,i,v,id))
{
w[g[u][i]][id]=z[g[u][i]]-z[id];
return 1;
}
}
return 0;
}

int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d%d",&x,&y,&z[i]);
a[i]=x,b[i]=y;
}
for (int i=1;i<n;i++) g[a[i]][b[i]]=g[b[i]][a[i]]=i;
memset(w,0,sizeof(w));
for (int i=n;i<=m;i++)
dfs(0,a[i],b[i],i);
km();
for (int i=1;i<n;i++) printf("%d\n",z[i]-lx[i]);
for (int i=n;i<=m;i++) printf("%d\n",z[i]+ly[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: