HDU 3488 Tour【KM】

题意: 给你一个包含 n 个城市的距离,并告诉你其中的一些路的距离,让你用一些环去覆盖所有点,且每个点只能覆盖一次,问环的最小城市多少。

分析:每个点只出现一次,而每一个点对应一个入的边和一个出的边,可以将入边放入 X 集合, 出边放入 Y 集合,二分该图,求其完全匹配下的最小权值

       匹配。

View Code
#include<stdio.h>
#include<string.h>
#define INF 0x1f1f1f
#define clr(x)memset(x,0,sizeof(x))
int sx[202],sy[202];
int lx[202],ly[202];
int link[202];
int map[202][202];
int n;
int find(int x)
{
    sx[x]=1;
    int i;
    for(i=1;i<=n;i++)
        if(!sy[i]&&lx[x]+ly[i]==map[x][i])
        {
            sy[i]=1;
            if(link[i]==0||find(link[i]))
            {
                link[i]=x;
                return 1;
            }
        }
    return 0;
}
int KM()
{
    int sum,i,j,v,dmin;
    for(i=1;i<=n;i++)
    {
        lx[i]=-INF;
        ly[i]=0;
        for(j=1;j<=n;j++)
            if(map[i][j]>lx[i])
                lx[i]=map[i][j];
    }
    clr(link);
    for(v=1;v<=n;v++)
        while(1)
        {
            clr(sx);  clr(sy);
            if(find(v)) break;
            dmin=INF;
            for(i=1;i<=n;i++)
                if(sx[i])
                    for(j=1;j<=n;j++)
                        if(!sy[j]&&lx[i]+ly[j]-map[i][j]<dmin)
                            dmin=lx[i]+ly[j]-map[i][j];
            for(i=1;i<=n;i++)
            {
                if(sx[i])
                lx[i]-=dmin;
                if(sy[i])
                ly[i]+=dmin;
            }
        }
    sum=0;
    for(i=1;i<=n;i++)
        sum+=map[link[i]][i];
    return sum;
}
int main()
{
    int i,j,t,m,a,b,w;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(map,-INF,sizeof(map));
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&w);
            if(-w>map[a][b])
                map[a][b]=-w;
        }
        printf("%d\n",-KM());
    }
    return 0;
}
posted @ 2012-04-24 17:35  'wind  阅读(187)  评论(0)    收藏  举报