• 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
    " , -ans) ;
        }
        return  0 ;
    }
    

  • 相关阅读:
    最近有人说我欺骗消费者,今天来一波视频分享
    前端 Java Python等资源合集大放送
    dubbo源码学习(四):暴露服务的过程
    dubbo源码学习(二) : spring 自定义标签
    Dubbo多注册中心和Zookeeper服务的迁移
    线程各种状态转换分析
    java并发之同步辅助类CountDownLatch
    工作5年的Java程序员,才学会阅读源码,可悲吗?
    【阿里面试系列】Java线程的应用及挑战
    「阿里面试系列」搞懂并发编程,轻松应对80%的面试场景
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7117205.html
Copyright © 2020-2023  润新知