zoukankan      html  css  js  c++  java
  • SYSU-4, UVA 12711, 一般图最大(小)权匹配

    题目大意:给你一个100个点的图,划分成两个点集,要求A点集所有点的度为奇数,B点集的点为偶数,求一个最小边权边集满足这个约束。

    解:我们要先抽象提炼一些性质,才能得到这题一般图最小匹配的做法

    首先一点,偶数点完全不用考虑,要么他们不选取,要么他们作为路径上的点即可(出度=入度),所以直接做一遍flyod,就可以把图变成只剩A点集的图了。

    第二点,就是对于一个合法答案,一条边不可能被选取两遍或以上,因为这样可以可以去掉两次这条边,依然可以得到一个合法图,而且答案更小,这是用来证明上面抽象图的做法的正确性。

    那么我们抽象了图以后,可以得知我们做一个最小匹配即可,因为这样能符合奇数点的约束,同时可以证明这样才是边权最小的选择(更大的图可以删边最终剩下匹配形式)

    一般图的最小权匹配做法很多,另外一位大神的blog介绍了一种消圈的做法,但是我被xzj安利了一个随机算法去弄,感觉效果不错,代码也短而且好理解。

    #include <cstdio>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <complex>
    #include <set>
    #include <vector>
    #include <map>
    #include <queue>
    #include <deque>
    #include <ctime>
    
    using namespace std;
    
    const double EPS = 1e-8;
    
    #define ABS(x) ((x)<0?(-(x)):(x))
    #define SQR(x) ((x)*(x))
    #define MIN(a,b) ((a)<(b)?(a):(b))
    #define MAX(a,b) ((a)>(b)?(a):(b))
    
    #define LSON(x) ((x)<<1)
    #define RSON(x) (((x)<<1)+1)
    #define LOWBIT(x) ((x)&(-(x)))
    #define MAXN 111
    #define LL long long
    #define OO 214748364
    
    int w[MAXN][MAXN], g[MAXN][MAXN];
    int match[MAXN], path[MAXN], d[MAXN], p[MAXN], len;
    bool v[MAXN];
    int n, m, k;
    
    void init() {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) g[i][j] = OO;
        for (int i = 0; i < m; ++i) {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            --x; --y;
            if (x == y) continue;
            if (z < g[x][y]) {
                g[x][y] = g[y][x] = z;
            }
        }
        for (int k = 0; k < n; ++k) 
            for (int i = 0; i < n; ++i) 
                for (int j = 0; j < n; ++j) 
                    g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
    
        for (int i = 0; i < k; ++i) {
            for (int j = 0; j < k; ++j) {
                w[i][j] = OO - g[i][j];
            }
        }
    }
    
    bool dfs(int i) {
        path[len++] = i;
        if (v[i]) return true;
        v[i] = true;
        for (int j = 0; j < k; ++j) {
            if (i != j && match[i] != j && !v[j]) {
                int kok = match[j];
                if (d[kok] < d[i] + w[i][j] - w[j][kok]) {
                    d[kok] = d[i] + w[i][j] - w[j][kok];
                    if (dfs(kok)) return true;
                }
            }
        }
        --len;
        v[i] = false;
        return false;
    }
    
    void solve() {
        if (k&1) {
            puts("Impossible");
            return ;
        }
        for (int i = 0; i < k; ++i) p[i] = i, match[i] = i ^ 1;
        int cnt = 0;
        for (;;) {
            len = 0;
            bool flag = false;
            memset(d, 0, sizeof(d));
            memset(v, 0, sizeof(v));
            for (int i = 0; i < k; ++i) {
                if (dfs(p[i])) {
                    flag = true;
                    int t = match[path[len - 1]], j = len - 2;
                    while (path[j] != path[len - 1]) {
                        match[t] = path[j];
                        swap(t, match[path[j]]);
                        --j;
                    }
                    match[t] = path[j];
                    match[path[j]] = t;
                    break;
                }
            }
            if (!flag) {
                if (++cnt >= 3) break;
                random_shuffle(p, p+k);
            }
        }
        int ans = 0;
        for (int i = 0; i < k; ++i) {
            int t = w[i][match[i]];
        //    cout << t << endl;
            if (t == 0) {
                puts("Impossible");
                return ;
            }
            ans += OO - t;
        }
        printf("%d
    ", ans / 2);
    }
    
    int main() {
        freopen("test.txt", "r", stdin);
        srand(time(0));
        int cas; scanf("%d", &cas);
        for (int tt = 1; tt <= cas; ++tt) {
            printf("Case %d: ", tt);
            init();
            solve();
        }
        return 0;
    }
    UVA12711
  • 相关阅读:
    使用360安全卫士在线对本机电脑进行重装系统
    分享个人电脑上的文件
    Docker初探之运行RabbitMQ消息队列服务
    Docker初探之运行MySQL
    Docker初探之常用命令实践
    Docker初探之Windows篇
    SignalR入门之多平台SignalR服务端
    SignalR入门之从外部访问持久性连接或Hub
    SignalR入门之Hub
    SignalR入门之小试身手
  • 原文地址:https://www.cnblogs.com/wmzisfoolish/p/5639893.html
Copyright © 2011-2022 走看看