Cyclic Tour (最优二分匹配or费用流)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853

 

Cyclic Tour

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others)
Total Submission(s): 3141    Accepted Submission(s): 1633


 

Problem Description

There are N cities in our country, and M one-way roads connecting them. Now Little Tom wants to make several cyclic tours, which satisfy that, each cycle contain at least two cities, and each city belongs to one cycle exactly. Tom wants the total length of all the tours minimum, but he is too lazy to calculate. Can you help him?

 

 

Input

There are several test cases in the input. You should process to the end of file (EOF).
The first line of each test case contains two integers N (N ≤ 100) and M, indicating the number of cities and the number of roads. The M lines followed, each of them contains three numbers A, B, and C, indicating that there is a road from city A to city B, whose length is C. (1 ≤ A,B ≤ N, A ≠ B, 1 ≤ C ≤ 1000).

 

 

Output

Output one number for each test case, indicating the minimum length of all the tours. If there are no such tours, output -1.

 

 

Sample Input

 

6 9

1 2 5

2 3 5

3 1 10

3 4 12

4 1 8

4 6 11

5 4 7

5 6 9

6 5 4

6 5

1 2 1

2 3 1

3 4 1

4 5 1

5 6 1

 

 

Sample Output

42

-1

 

【题目大意】

找几个环,保证环之间无公共点,并且保证找到的环权值最大;

【题目思路】

1、我们首先要知道一个结论(其实想想画画就明白了)如果给定一张有向图,里面所有的点的入度和出度都为1,那么该图一定是由若干个不相交的环构成的。

2、既然我们要找出若干个环使得总路径最短,那么我们只要去用已知信息去建图使得每个点的入度出度只为1,且总权值最小即可。

 因此我们可以把一个点拆成两个点,分别表示出度及入度,然后去找拆点后构成的二分图的完美匹配。也可以用网络流来做。

本文选用KM,因为更快。

3、注意一个很坑的地方,数据可能有重边,选权值小的即可。

 

【代码】

#include
const int maxn = 101;
const int INF = 0xffffff;
int w[maxn][maxn];
int lx[maxn],ly[maxn]; //顶标
int linky[maxn];
int visx[maxn],visy[maxn];
int slack[maxn];
int nx,ny;
bool find(int x)
{
    visx[x] = true;
    for(int y = 1; y <= ny; y++)
    {
        if(visy[y])
            continue;
        int t = lx[x] + ly[y] - w[x][y];
        if(t==0)
        {
            visy[y] = true;
            if(linky[y]==-1 || find(linky[y]))
            {
                linky[y] = x;
                return true;        //找到增广轨
            }
        }
        else if(slack[y] > t)
            slack[y] = t;
    }
    return false;                   //没有找到增广轨(说明顶点x没有对应的匹配,与完备匹配(相等子图的完备匹配)不符)
}

int KM()                //返回最优匹配的值
{
    int i,j;

    memset(linky,-1,sizeof(linky));
    memset(ly,0,sizeof(ly));
    for(i = 1; i <= nx; i++)
        for(j = 1,lx[i] = -INF; j <= ny; j++)
            if(w[i][j] > lx[i])
                lx[i] = w[i][j];
    for(int x = 1; x <= nx; x++)
    {
        for(i = 1; i <= ny; i++)
            slack[i] = INF;
        while(true)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(find(x))                     //找到增广轨,退出
                break;
            int d = INF;
            for(i = 1; i <= ny; i++)          //没找到,对l做调整(这会增加相等子图的边),重新找
            {
                if(!visy[i] && d > slack[i])
                    d = slack[i];
            }
            for(i = 1; i <= nx; i++)
            {
                if(visx[i])
                    lx[i] -= d;
            }
            for(i = 1; i <= ny; i++)
            {
                if(visy[i])
                     ly[i] += d;
                else
                     slack[i] -= d;
            }
        }
    }
    int result = 0;
    /*for(i = 1; i <= ny; i++)
    if(linky[i]>-1)
        result += w[linky[i]][i];
    return result;*/
    for(i = 1; i <=nx; i++)
    {
        if(linky[i]==-1||w[linky[i]][i]==-INF)
        return 1;
        else    result += w[linky[i]][i];
    }
    return result;

}

int main()
{
  int m,n;
    while(scanf("%d%d",&n,&m)==2)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            w[i][j]=-INF;
        }

        for(int i=1;i<=m;i++)
        {
           int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
           if(-c>w[a][b])//因为可能有重边
           w[a][b]=-c;

        }
        nx=ny=n;
        printf("%d\n",-KM());
    }
    return 0;
}
 

 

 

 

 

你可能感兴趣的:(算法,KM算法)