POJ 1274 The Perfect Stall 【二分图匹配】

89 篇文章 0 订阅
16 篇文章 0 订阅

裸的二分图匹配


匈牙利算法:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
#define N 220
int n, m;
vector<int> adj[N];
int pre[N];
bool used[N];

bool CrossPath(int k) {
    for (int i=0; i<adj[k].size(); i++) {
        int j=adj[k][i];
        if (!used[j]) {
            used[j]=true;
            if (pre[j]==0 || CrossPath(pre[j])) {
                pre[j]=k;
                return true;
            }
        }
    }
    return false;
}
int hungary() {
    int match = 0;
    memset(pre, 0, sizeof(pre));
    for (int i=1; i<=n; i++) {
        memset(used, false, sizeof(used));
        if (CrossPath(i))
            match++;
    }
    return match;
}
int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        int b, c;
        for (int i=1; i<=n; i++) {
            adj[i].clear();
            scanf("%d", &c);
            while (c--) {
                scanf("%d", &b);
                adj[i].push_back(b);
            }
        }
        cout << hungary() << endl;
    }
    return 0;
}


转化为最大流(这个最大流的模板存储图的方式有点低效了,但是算法整体的时间还是挺不错的):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define N 420
#define INF 0x3f3f3f3f
class Dinic {
public:
    int c[N][N], n, s, t, l[N], e[N];
    int flow(int maxf = INF) {
        int left = maxf;
        while (build()) left -= push(s, left);
        return maxf - left;
    }
    int push(int x, int f) {
        if (x == t) return f;
        int &y = e[x], sum = f;
        for (; y<n; y++)
            if (c[x][y] > 0 && l[x]+1==l[y]) {
                int cnt = push(y, min(sum, c[x][y]));
                c[x][y] -= cnt;
                c[y][x] += cnt;
                sum -= cnt;
                if (!sum) return f;
            }
        return f-sum;
    }
    bool build() {
        int m = 0;
        memset(l, -1, sizeof(l));
        l[e[m++]=s] = 0;
        for (int i=0; i<m; i++) for (int y=0; y<n; y++)
            if (c[e[i]][y] > 0 && l[y]<0) l[e[m++]=y] = l[e[i]] + 1;
        memset(e, 0, sizeof(e));
        return l[t] >= 0;
    }
} net;
int main() {
    int n, m, a, b;
    while (scanf("%d%d", &n, &m) == 2) {
        memset(net.c, 0, sizeof(net.c));
        net.s = 0, net.t = n+m+1, net.n = n+m+2;

        for (int i=1; i<=n; i++) net.c[net.s][i] = 1;
        for (int i=1; i<=m; i++) net.c[n+i][net.t] = 1;

        for (int i=1; i<=n; i++) {
            cin >> a;
            while (a--) {
                cin >> b;
                net.c[i][n+b] = INF;
            }
        }
        cout << net.flow() << endl;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值