zoukankan      html  css  js  c++  java
  • HDU3488 Tour 再次感受到KM的强大

    题意:这题自己YY了下,没想到结论还是对的。题目告诉我们一个有向图,现在问将图中的每一个点都划分到一个环中的最少代价是多少?每条边都有一个代价。

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

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

    代码如下:

    #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\n", -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;    
    }
  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/Lyush/p/3025145.html
Copyright © 2011-2022 走看看