hdu3488Tour KM算法

//给一个有向图,
//找出若干环,使得这些环覆盖全部点且每一个点仅仅能在一个环中
//问所得的全部环的全部边权值之和的最小值为多少
//对于每一个点仅仅有一个入度和一个出度。那么将每一个点拆成
//入度点和出度点,将全部入度点和全部出度点构成一个完备匹配
//因为是完备匹配,所以每一个点的出度和入度都有一个不是自己的点
//相连,那么将完备匹配的全部点连接起来一定是若干环
//所得完备匹配的最小匹配即为答案
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 210 ;
const int inf = 0x3f3f3f3f ;
int lx[maxn] , ly[maxn] , slack[maxn] ;
int visx[maxn] , visy[maxn] , match[maxn] ;
int map[maxn][maxn] ;
int n  , m ;
int find(int x)
{
    visx[x] = 1 ;
    for(int i = 1;i <= n;i++)
    {
        if(visy[i])continue ;
        int tmp = lx[x] + ly[i] - map[x][i] ;
        if(tmp == 0)
        {
            visy[i] = 1 ;
            if(match[i] == -1 || find(match[i]))
            {
                match[i] = x ;
                return true ;
            }
        }
        else slack[i] = min(slack[i] , tmp) ;
    }
    return false ;
}
int KM()
{
    memset(ly , 0 , sizeof(ly)) ;
    memset(match , -1 , sizeof(match)) ;
    for(int i = 1;i <= n;i++)
    {
        lx[i] = -inf ;
        for(int j = 1;j <= n;j++)
        lx[i] = max(lx[i] , map[i][j]) ;
    }
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= n;j++)
        slack[j] = inf ;
        while(1)
        {
            memset(visx , 0 ,sizeof(visx)) ;
            memset(visy , 0 ,sizeof(visy)) ;
            if(find(i))break ;
            int d = inf ;
            for(int j = 1;j <= n;j++)
            if(!visy[j])
            d = min(d , slack[j]) ;
            for(int j = 1;j <= n;j++)
            if(visx[j])
            lx[j] -= d ;
            for(int j = 1;j <= n;j++)
            if(visy[j])
            ly[j] += d ;
            else slack[j] -=d ;
        }
    }
    int ans = 0 ;
    for(int i = 1;i <= n;i++)
    ans += map[match[i]][i] ;
    return ans ;
}
int main()
{
    int t ;
    scanf("%d" , &t) ;
    while(t--)
    {
        scanf("%d%d" , &n , &m) ;
        for(int i = 1;i <= n;i++)
          for(int j = 1;j <= n;j++)
           map[i][j] = -inf ;
        while(m--)
        {
            int u , v , w ;
            scanf("%d%d%d" , &u , &v , &w) ;
            if(u != v && -w > map[u][v])
            map[u][v]  = -w ;
        }
        int ans = KM() ;
        printf("%d\n" , -ans) ;
    }
    return  0 ;
}

posted on 2017-07-04 16:24  slgkaifa  阅读(132)  评论(0编辑  收藏  举报

导航