• hdu1853 Cyclic Tour (二分图匹配KM)


    Cyclic Tour

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


    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
    Hint
    In the first sample, there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42.
     
    题意:给一个有向有权图,选一些边使得每个点都在且只在一个环之中,且要求权值走过的边的权值最小
     
    思路:

        可以发现,每个点的入度和出度都是1。

           如果每个点都拆成入点和出点,对于点u,可以拆成u和u’, u是入点,u’是出点。

           若有边(u, v),则u’ -> v连边

           这样整个图转化为一个二分图。由于每个入点需要找一个出点连接,每个出点也要找一个入点连接,那么就是经典的二分图匹配问题。加上一个权值,就是二分图最优匹配问题。用KM或者最小费用流都可以解决。

    这题卡了几天,因为KM模版都是每一个x点都和每一个y点连上了,而这条题目只是部分连了而已,不懂得处理

    后来看题解处理方法只是最后统计答案的时候,如果g[linker[y]][y]==-INF的话就跳过

    求最小匹配的处理就是把权值换成负的就可以了

    第一次交wa了,因为没考虑到重边的情况,这些题要考虑判重自环呀

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <utility>
    #include <queue>
    #include <stack>
    using namespace std;
    const int INF=1e9;
    const double eps=1e-6;
    const int N = 210;
    
    int nx,ny;
    int g[N][N];
    int linker[N],lx[N],ly[N];// x is outpoint, y is inpoint
    int slack[N];
    int visx[N],visy[N];
    
    int n,m;
    
    bool DFS(int x)
    {
        visx[x]=true;
        for(int y=0;y<ny;y++)
        {
            if(visy[y]) continue;
            int tmp = lx[x]+ly[y]-g[x][y];
            if(tmp==0)
            {
                visy[y]=true;
                if(linker[y]==-1||DFS(linker[y]))
                {
                    linker[y]=x;
                    return true;
                }
            }
            else if(slack[y]>tmp)
                slack[y]=tmp;
        }
        return false;
    }
    
    int KM()
    {
        memset(linker,-1,sizeof(linker));
        memset(ly,0,sizeof(ly));
        for(int i=0;i<nx;i++)
        {
            lx[i]=-INF;
            for(int j=0;j<ny;j++)
                if(g[i][j]>lx[i])
                    lx[i]=g[i][j];
        }
        for(int x=0;x<nx;x++)
        {
            for(int i=0;i<ny;i++)
                slack[i]=INF;
            while(true)
            {
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if(DFS(x)) break;
                int d = INF;
                for(int i=0;i<ny;i++)
                    if(!visy[i] && d>slack[i])
                        d=slack[i];
                for(int i=0;i<nx;i++)
                    if(visx[i])
                        lx[i]-=d;
                for(int i=0;i<ny;i++)
                {
                    if(visy[i]) ly[i]+=d;
                    else slack[i]-=d;
                }
            }
        }
        int res = 0, cnt = 0;
        for(int i=0;i<ny;i++)
        {
            if(linker[i]==-1 || g[linker[i]][i]==-INF)
                continue;
            res += g[linker[i]][i];
            cnt++;
        }
        if(cnt!=nx) return -1;
        return -res;
    }
    
    void run()
    {
    //    memset(g,0,sizeof(g));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                g[i][j]=-INF;
        int u,v,c;
        while(m--)
        {
            scanf("%d%d",&u,&v);
            scanf("%d",&c);
            if(-c>g[u-1][v-1])
                g[u-1][v-1]=-c;
        }
        nx=ny=n;
        printf("%d
    ",KM());
    }
    
    int main()
    {
        #ifdef LOCAL
        freopen("case.txt","r",stdin);
        #endif // LOCAL
        while(scanf("%d%d",&n,&m)!=EOF)
            run();
        return 0;
    }
  • 相关阅读:
    手机如何当电脑的摄像头使用
    内网穿透软件
    如何在laravel框架中使用阿里云的oss
    css position 定位详解
    laravel 速查表
    window10如何查看连接过的wifi密码
    sweetalert弹出层组件
    phpstudy安装 与phpstudy_Windows web面板安装
    程序员修炼之道读后感
    JAVA-WEB-简单的四则运算
  • 原文地址:https://www.cnblogs.com/someblue/p/4027628.html
Copyright © 2020-2023  润新知