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\n", 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM