zoukankan      html  css  js  c++  java
  • Tour(二分图最大权匹配)(网络流)

    Tour
    Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u

    Description

    In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain one or more loops. (A loop is a route like: A->B->……->P->A.) 
    Every city should be just in one route. 
    A loop should have at least two cities. In one route, each city should be visited just once. (The only exception is that the first and the last city should be the same and this city is visited twice.) 
    The total distance the N roads you have chosen should be minimized. 
     

    Input

    An integer T in the first line indicates the number of the test cases. 
    In each test case, the first line contains two integers N and M, indicating the number of the cities and the one-way roads. Then M lines followed, each line has three integers U, V and W (0 < W <= 10000), indicating that there is a road from U to V, with the distance of W. 
    It is guaranteed that at least one valid arrangement of the tour is existed. 
    A blank line is followed after each test case.
     

    Output

    For each test case, output a line with exactly one integer, which is the minimum total distance.
     

    Sample Input

    1 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
     

    Sample Output

    42




    题意:给你一个有向图,边有权值,现在要你求若干个环包含所有的顶点,并且每个顶点只出现一次(除了一个环中的起始点)使得华中所有边得权值之和最小。(这道题没有说明没有环的情况,直接按照都有环的情况做就行了)

    由于要成环,那么将这个图进行拆点,就变成了单向的二分图了,此时一个完备匹配就是一种连线策略,只要保证没有边是和自己相连,就能够满足题目中要求的每个点至少属于一个环。证明也是很简单的。因为我们总可以从一个完备匹配中找出起点,然后再从匹配点作为起点找......

    上图可以看做是1,2成环,3,4,5成环。


    像这杨构成圈并且每个点只能属于一个圈的题, 可以转化成2 分图, 每个点只能属于一个圈, 那么出度和入度必定为1 , 那么把一个点拆开i, i`, i控制入读, i` 控制出度, 流量只能为1 。 那么对于原来途中有的边 可以 i - > j`, j - > i`;连起来构图, 然后建立超级远点s,超级汇点t,s - > i , i` - > t ; 然后求最小费用流。。这样就抱着了每个点只能属于一个圈, 因为入读 == 出度 == 1 ;这类也问题可以  做为判断性问题出。


    因为出入度 都是1 所以也可以用 km 求最值。。

    代码:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    int N, M;
    
    const int INF = 0x3f3f3f3f;
    int w[205][205];
    int lx[205], ly[205];
    int sx[205], sy[205];
    int match[205], slack[205];
    
    int path(int u) {
        sx[u] = 1;
        for (int i = 1; i <= N; ++i) {
            if (sy[i]) continue;
            int t = lx[u] + ly[i] - w[u][i];
            if (!t) {
                sy[i] = 1;
                if (!match[i] || path(match[i])) {
                    match[i] = u;
                    return true;
                }
            } else {
                slack[i] = min(slack[i], t);
            }
        }
        return false;
    }
    
    void KM() {
        memset(match, 0, sizeof (match));
        memset(lx, 0x80, sizeof (lx));
        memset(ly, 0, sizeof (ly));
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) { 
                lx[i] = max(lx[i], w[i][j]);
            }
        }
        for (int i = 1; i <= N; ++i) {
            memset(slack, 0x3f, sizeof (slack));
            while (1) {
                memset(sx, 0, sizeof (sx));
                memset(sy, 0, sizeof (sy));
                if (path(i)) break;
                int d = INF;
                for (int j = 1; j <= N; ++j) {
                    if (!sy[j]) d = min(d, slack[j]);
                }
                for (int j = 1; j <= N; ++j) {
                    if (sx[j]) lx[j] -= d;
                    if (sy[j]) ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        int ret = 0;
        for (int i = 1; i <= N; ++i) {
            ret += w[match[i]][i];
        }
        printf("%d
    ", -ret);
    }
    
    int main() {
        int T, x, y, ct;
        scanf("%d", &T);
        while (T--) {
            scanf("%d %d", &N, &M);
            memset(w, 0x80, sizeof (w));
            for (int i = 1; i <= M; ++i) {
                scanf("%d %d %d", &x, &y, &ct);
                w[x][y] = max(w[x][y], -ct);
            }
            KM();
        }
        return 0;    
    }

    用最小费用最大流:

    http://www.tuicool.com/articles/aUBvyeN





  • 相关阅读:
    ArcMap影像纠偏
    关于ArcGIS动态图层空间内栅格数据,JS前端显示颜色不正确的解决方案
    发布镶嵌数据集,服务端Raster Function制作
    ARCGIS 发布TIF,金字塔文件是否Server自动生成。
    验证航行数据
    解决PLSQL Developer 插入中文 乱码问题
    ArcGIS发布动态空间,并验证
    老丫么老毛桃
    使用IIS建立主机到虚拟机的端口转发
    最大子序列求和算法二三
  • 原文地址:https://www.cnblogs.com/zswbky/p/6717972.html
Copyright © 2011-2022 走看看