1. 程式人生 > >Cyclic Tour(HDU-1853)

Cyclic Tour(HDU-1853)

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

————————————————————————————————————————————————————

題意:給一個 n 個點 m 條邊的帶權有向圖,現要求這 n 個點正好被 1 或多個不相交的有向環覆蓋,求這些有向環的最小邊權值

思路:可以將 n 個點分為兩部分,i 與 i‘,分別作為左右點集,因此若原圖中存在邊(i,j),則二分圖中存在(i,j'),從而建圖

若原圖能由多個不相交的有向環覆蓋,那麼二分圖一定存在完全匹配,比如:原圖中有向環為 1-2-3-1,則二分圖的完全匹配就是 1-2',2-3',3-1'

由於有向環覆蓋對應一個二分圖的完全匹配,該完全匹配的權值對應有向環覆蓋的權值,因此原圖權值最大的有向環匹配就是二分圖最優匹配的值

題目要求邊權值最小,因此將所有邊取負數,再使用 KM 演算法,得到的值再取負即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-6
#define MOD 16007
#define INF 0x3f3f3f3f
#define N 1001
#define LL long long
using namespace std;
int n,m;
int G[N][N];
int Lx[N],Ly[N];
bool visX[N],visY[N];
int linkX[N],linkY[N];
bool dfs(int x){
    visX[x]=true;
    for(int y=1;y<=n;y++){
        if(!visY[y]){
            int temp=Lx[x]+Ly[y]-G[x][y];
            if(temp==0){
                visY[y]=true;
                if(linkY[y]==-1 || dfs(linkY[y])){
                    linkX[x]=y;
                    linkY[y]=x;
                    return true;
                }
            }
        }
    }
    return false;
}
void update(){
    int minn=INF;
    for(int i=1;i<=n;i++)
        if(visX[i])
            for(int j=1;j<=n;j++)
                if(!visY[j])
                    minn=min(minn,Lx[i]+Ly[j]-G[i][j]);

    for(int i=1;i<=n;i++)
        if(visX[i])
            Lx[i]-=minn;

    for(int i=1;i<=n;i++)
        if(visY[i])
            Ly[i]+=minn;
}
int KM(){
    memset(linkX,-1,sizeof(linkX));
    memset(linkY,-1,sizeof(linkY));

    for(int i=1;i<=n;i++){
        Lx[i]=Ly[i]=0;
        for(int j=1;j<=n;j++)
            Lx[i]=max(Lx[i],G[i][j]);
    }

    for(int i=1;i<=n;i++){
        while(true){
            memset(visX,false,sizeof(visX));
            memset(visY,false,sizeof(visY));

            if(dfs(i))
                break;
            else
                update();
        }
    }

    int ans=0;
    for(int i=1;i<=n;i++){
        if(G[linkY[i]][i]==-INF){
            return 1;
        }
        ans+=G[linkY[i]][i];
    }

    return ans;
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                G[i][j]=-INF;

        while(m--){
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            G[x][y]=max(G[x][y],-w);//可能有重邊
        }
        printf("%d\n",-KM());
    }
    return 0;
}