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;
}

 

posted @ 2012-08-07 16:33  gabo  阅读(302)  评论(0编辑  收藏  举报