1. 程式人生 > 實用技巧 >二分圖板子

二分圖板子

二分圖最大匹配:

匈牙利演算法 鄰接表O(mn):

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1010;
const int maxm = 2e5;
int n, m, t;
int mch[maxn], vistime[maxn];

struct E {
    int to, next;
}edge[maxm];

int tot, head[maxn];

void init()
{
    memset(vistime, 0, sizeof(vistime));
    memset(head, 
-1, sizeof(head)); tot = 0; } inline void add_edge(int u, int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } bool Hungarian(int u, int tag) { if (vistime[u] == tag) return 0; vistime[u] = tag; for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to; if ((mch[v] == 0) || Hungarian(mch[v], tag)) { mch[v] = u; return 1; } } return 0; } int main() { scanf("%d%d%d", &n, &m, &t); init(); while (t--) { int u, v; scanf("%d%d", &u, &v); add_edge(u, v); }
int ans = 0; for (int i = 1; i <= n; ++ i) if (Hungarian(i, i)) ++ans; printf("%d\n", ans); return 0; }
View Code

KM演算法  O(N^3):

#include <bits/stdc++.h>
using namespace std;

const int maxn = 501;
const int maxm = 250001;
const int inf = 0x3f3f3f3f;

int nl, nr, m;
int tot, head[maxn];
int ans, linkx[maxn], linky[maxn];
int dx[maxn], dy[maxn];

struct E {
    int to, next;
}edge[maxm]; //這裡千萬要注意,如果題目是雙向邊的話,這裡的N要開2*N

inline void read(int& ans)
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch<'0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while ( ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    ans =  x * f;
}
//加邊
inline void add_edge(int u, int v) {
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
    if (!linkx[u] && !linky[v])
        linky[v] = u, linkx[u] = v, ++ ans;
}

bool bfs()
{
    bool ret=0;
    queue<int> q;
    memset(dx, 0, sizeof(dx)), memset(dy, 0, sizeof(dy));
    for (int i = 1; i <= nl; ++ i)
        if (!linkx[i]) q.push(i);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            if (!dy[v]) {
                dy[v] = dx[u] + 1;
                if (!linky[v]) ret = 1;
                else dx[linky[v]] = dy[v]+1, q.push(linky[v]);
            }
        }
    }
    return ret;
}

bool dfs(int u)
{
    for (int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if (dy[v] == dx[u] + 1) {
            dy[v] = 0;
            if (!linky[v] || dfs(linky[v])) {
                linky[v] = u, linkx[u] = v;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    int a, b;
    memset(head, -1, sizeof(head));
    read(nl), read(nr), read(m);
    for (int i = 1; i <= m; ++ i)
        read(a), read(b), add_edge(a,b);

    while(bfs()) {
        for (int i = 1; i <= nl; ++ i)
            if (!linkx[i] && dfs(i))
                ++ ans;
    }

    printf("%d\n",ans);
//  這段迴圈是用來輸出跟誰匹配 
//    for (int i = 1; i <= nl; ++ i)
//        printf("%d ",linkx[i]);

    return 0;
}
View Code