SGU252 Railway Communication(二分图最大权匹配)

题目链接

题意:
        某国有 n 个城镇, m 条单向铁路。每条铁路都连接着两个不同的城镇,且该铁路系统中不存在环。现需要确定一些列车运行线,使其满足:
        1     每条铁路最多属于一条列车运行线;
        2     每个城镇最多被一条列车运行线通过(通过包括作为起点或终点);
        3     每个城镇至少被一条列车运行线通过;
        4     列车运行线的数量应尽量小。
        5     在满足以上条件下列车运行线的长度和应该尽量小。


思路:
        05 年的论文题, 将每个点 u 拆成入点 u 和出点 u ,对于 ( u , v ) 这条有向边, u v 连接一条有向边, 权值为该路径长度的负值,然后就是求一个二分图最大权匹配, 求得的最大值的负数值即为原路径长度最小值。然后找一下求解出来的路径, 一条路径如果是起点,那么它只有出点, 也就是说 u 是起点的话, 只有 u 有匹配边而 u 没有匹配边,同样 u 如果是终点的话只有 u 有匹配边而 u 没有,寻找一下就好了, 注意有可能只有一个点的情况。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<iostream>
typedef long long ll;
const int maxn = 1e2 + 10;
const int INF = 1e9;
using namespace std;

typedef pair<int, int> pa;
vector<pa> G[maxn];

int w[maxn][maxn], n;
int lx[maxn], ly[maxn];
int from[maxn], m;
bool S[maxn], T[maxn];

bool match(int i) {
    S[i] = true;
    for(int j = 1; j <= n; j++) {
        if(lx[i] + ly[j] != w[i][j] || T[j]) continue;
        T[j] = true;
        if(!from[j] || match(from[j])) {
            from[j] = i;
            return true;
        }
    }
    return false;
}

void update() {
    int a = 1 << 30;
    for(int i = 1; i <= n; i++) {
        if(!S[i]) continue;
        for(int j = 1; j <= n; j++) {
            if(T[j]) continue;
            a = min(a, lx[i] + ly[j] - w[i][j]);
        }
    }
    for(int i = 1; i <= n; i++) {
        if(S[i]) lx[i] -= a;
        if(T[i]) ly[i] += a;
    }
}

void KM() {
    for(int i = 1; i <= n; i++) {
        from[i] = lx[i] = ly[i] = 0;
        for(int j = 1; j <= n; j++) {
            lx[i] = max(lx[i], w[i][j]);
        }
    }
    for(int i = 1; i <= n; i++) {
        while(1) {
            for(int j = 1; j <= n; j++) S[j] = T[j] = 0;
            if(match(i)) break;
            else update();
        }
    }
}

int vis[maxn], to[maxn];
vector<int> vec[maxn];

int main() {
    while(scanf("%d %d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++) w[i][j] = -INF;
        for(int i = 1; i <= m; i++) {
            int u, v, c;
            scanf("%d %d %d", &u, &v, &c);
            w[u][v] = -c;
        }
        KM();
        int ans = 0, num = 0;
        for(int i = 1; i <= n; i++) if(w[from[i]][i] != -INF) ans += w[from[i]][i];
        memset(vis, 0, sizeof vis);
        memset(to, -1, sizeof to);
        for(int i = 0; i < maxn; i++) vec[i].clear();
        for(int i = 1; i <= n; i++) {
            if(w[from[i]][i] != -INF) {
                to[from[i]] = i;
                vis[i] = 1;
            }
        }
        for(int i = 1; i <= n; i++) {
            if(to[i] == -1 && !vis[i]) { vec[num].push_back(i); num++; continue; }
            if(~to[i] && !vis[i]) { ///起始点
                int x = i;
                while(~x) {
                    vec[num].push_back(x);
                    x = to[x];
                }
                num++;
            }
        }
        printf("%d %d\n", num, -ans);
        for(int i = 0; i < num; i++) {
            printf("%d", vec[i].size());
            for(int j = 0; j < vec[i].size(); j++) printf(" %d", vec[i][j]);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hnust_Derker/article/details/80065832