您的位置:首页 > 其它

hdu 3488 Tour (km 二分图 最小权)

2012-05-08 21:34 344 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3488
/*
一开始看题完全蒙了 ,这怎么用二分图解啊,后来开了别人的结题报告
将图中的 入点放到 x集合 出点放到 y集合 看作二分图求解
但是还有一个疑问,为什么看成这样求出来的即使答案呢?
后来仔细想了想,原来  每个点的入点 出现在x集合 那么起出点 也相应的会出现在 x集合
因为每一个点都有至少 一个出点,这样构成的二分图 求其 最小权匹配 即可
*/

#include<stdio.h>
#define maxn 300
#include<string.h>
#define inf 0x6ffffff
int n,m;
int lx[maxn],ly[maxn],visx[maxn],visy[maxn],slack[maxn];
int linky[maxn];
int w[maxn][maxn];
int find(int x)
{
visx[x]=1;
for(int y=1;y<=n;y++)
{
if(visy[y])continue;
int t=lx[x]+ly[y]-w[x][y];
if(t==0)
{
visy[y]=1;
if(linky[y]==-1||find(linky[y]))
{
linky[y]=x;
return 1;
}

}
else
if(slack[y]>t)slack[y]=t;

}
return 0;

}
int KM()
{
int i,j;
memset(linky,-1,sizeof(linky));
memset(ly,0,sizeof(ly));
for(i=1;i<=n;i++)
{
lx[i]=-inf;//与最大权的不同
for(j=1;j<=n;j++)
{
if(lx[i]<w[i][j])
lx[i]=w[i][j];
}
}
for(int x=1;x<=n;x++)
{
for(i=1;i<=n;i++)
slack[i]=inf;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(find(x))break;
int d=inf;
for(i=1;i<=n;i++)
{
if(!visy[i]&&d>slack[i])d=slack[i];

}
for(i=1;i<=n;i++)
{
if(visx[i])lx[i]-=d;
}
for(i=1;i<=n;i++)
{
if(visy[i])ly[i]+=d;
else slack[i]-=d;
}
}
}
int ans=0;
for(i=1;i<=n;i++)
{
if(linky[i]==-1||w[linky[i]][i]==-inf)return 1;//这里判断是否有完全匹配
else
ans+=w[linky[i]][i];
}
return ans;
}
int main()
{
int T,i,j,a,b,c;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
w[i][j]=-inf;
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(-c>w[a][b])
w[a][b]=-c;//与最大全的不同
}
printf("%d\n",-KM());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: