zoukankan      html  css  js  c++  java
  • KM求最优匹配 hdu 3488 Tour

    KM求最优匹配 hdu 3488 Tour
    //KM求最优匹配  hdu 3488 Tour
    
    //题意:
    //给出两个端点和这两点间的距离,求出这些边构成的所有环中
    //边和最小是多少,每个点只能用一次,即每个点只能在一个环中
    
    //思路:
    //把每个点拆成两个点,每条边的出度点(起点) 作为x部,入度点(终点) 作为y部
    //然后进行最优匹配就是答案了(想知道为什么,画画图想一想就知道了,不知道怎么说)
    //因为题目保证有解
    
    //注意:
    //1、KM是求最优匹配,求的是最大值,所以边要先加个负号求
    //出答案后再加个负号输出就可以了
    //2、visy标记的是不需要松弛的点,在hungary中若lx[from] + ly[to] == map[from][to]
    //则to点不需要松弛,visy[to]标记为true,若小于的话则需要松弛,
    //松弛完就有可能跟x部的点得到上面等式相等的情况,就可能增加一对匹配
    
    #define infile freopen("in.txt", "r", stdin);
    #include <stdio.h>
    #include <string.h>
    
    #define INF (1<<30)
    #define N 205
    
    int n_node, eid;
    int map[N][N];
    int head[N], lx[N], ly[N], right[N], slack[N];
    bool visx[N], visy[N];
    
    bool hungary(int now)
    {
        visx[now] = true;
        for(int i = 1; i <= n_node; ++i)
        {
            if(map[now][i] != INF)
            {
                if(visy[i] == true)
                    continue;
                int slck = lx[now] + ly[i] - map[now][i];
                if(slck == 0)   //不需要松弛,这是匹配的前提
                {
                    visy[i] = true; //不需要松弛的话就标记起来
                    if(right[i] == 0 || hungary(right[i]))
                    {
                        right[i] = now;
                        return true;
                    }
                }
                else
                    slack[i] = slck < slack[i] ? slck : slack[i];
            }
        }
        return false;
    }
    
    void KM()
    {
        for(int i = 1; i <= n_node; ++i)
        {
            for(int j = 1; j <= n_node; ++j)
                slack[j] = INF;
            while(1)
            {
                for(int j = 1; j <= n_node; ++j)
                    visx[j] = visy[j] = false;
    
                if(hungary(i))
                    break;
    
                int min = INF;
                for(int j = 1; j <= n_node; ++j)//在需要松弛(visy[j]==false)的点中
                    if(visy[j] == false && min > slack[j])//找出最小松弛量
                        min = slack[j];
    
                for(int j = 1; j <= n_node; ++j)
                {
                    if(visx[j] == true)
                        lx[j] -= min;
                    if(visy[j] == true)
                        ly[j] += min;
                    else
                        slack[j] -= min;
                }
            }
        }
        int ans = 0;
        for(int i = 1; i <= n_node; ++i)
            ans += map[right[i]][i];
        printf("%d\n", -ans);
    }
    
    int main()
    {
        int n_case;
        scanf("%d", &n_case);
        while(n_case--)
        {
            int n_edge;
            scanf("%d%d", &n_node, &n_edge);
    
            eid = 0;
            for(int i = 0; i <= n_node; ++i)
            {
                lx[i] = -INF;
                ly[i] = 0;
                right[i] = 0;
                for(int j = i; j <= n_node; ++j)
                    map[i][j] = map[j][i] = -INF;
            }
            for(int i = 1; i <= n_edge; ++i)
            {
                int from, to, d;
                scanf("%d%d%d", &from, &to, &d);
                if(map[from][to] < -d)
                {
                    map[from][to] = -d;
                    if(lx[from] < -d)
                        lx[from] = -d;
                }
            }
            KM();
        }
        return 0;
    }
  • 相关阅读:
    [BZOJ3195] [Jxoi2012]奇怪的道路
    Splay Tree
    区间DP复习
    Link Cut Tree
    [BZOJ2734] [HNOI2012]集合选数
    如何写出杀手级简历(针对程序员) (转)
    30个提高Web程序执行效率的好经验(转)
    Oracle中的SQL跟踪( 转)
    如何终止SQL Server中的用户进程(转)
    Will the real programmers please stand up?(转)
  • 原文地址:https://www.cnblogs.com/gabo/p/2626946.html
Copyright © 2011-2022 走看看