[UOJ79]一般图最大匹配

模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

#define N 2500

using namespace std;

int fa[N],t,n,m;
bool g[N][N];
int gf(int x) { return fa[x] == x ? x : fa[x] = gf(fa[x]); }
void unit(int a,int b) { 
    a = gf(a) , b = gf(b);
    if (a != b) fa[a] = b;
}

int match[N];
vector<int> e[N];
int Q[N],rear;
int nex[N],mark[N],vis[N];

int LCA(int x,int y) {
    ++t;
    for (;;swap(x,y)) if (x){
        x = gf(x); 
        if (vis[x] == t) return x;
        vis[x] = t;
        x = nex[ match[x] ];
    }
}

void group(int a,int p) {
    while (a != p) {
        int b = match[a] , c = nex[b];
        if (gf(c) != p) nex[c] = b;
        if (mark[b] == 2) mark[Q[++rear] = b] = 1;
        //if (mark[c] == 2) mark[Q[++rear] = c] = 1;
        unit(a,b); unit(b,c);
        a = c; 
    }
}

void aug(int S) {
    for (int i=1;i<=n;i++) 
        nex[i] = mark[i] = vis[i] = 0;
    for (int i=1;i<=n;i++) fa[i] = i;
    mark[S] = 1; Q[1] = S; rear = 1;
    for (int head=1;/*!match[S] &&*/ head<=rear;head++) {
        int x = Q[head];
        for (int i=0;i<(int)e[x].size();i++) {
            int y = e[x][i];
            if (match[x] == y) continue;
            if (gf(x) == gf(y)) continue;
            if (mark[y] == 2) continue;
            if (mark[y] == 1) {
                int r = LCA(x,y);
                if (gf(x) != r) nex[x] = y;
                if (gf(y) != r) nex[y] = x;
                group(x,r); group(y,r);
            } else {
                if (match[y] == 0)  {
                    nex[y] = x;
                    for (int u=y;u;) {
                        int v = nex[u];
                        int mv = match[v];
                        match[u] = v; match[v] = u;
                        u = mv;
                    }
                    //break;
                    return;
                } else {
                    nex[y] = x;
                    mark[ Q[++rear] = match[y] ] = 1;
                    mark[y] = 2;
                }
            }
        }
    }

}

int main() {
    scanf("%d%d",&n,&m);
    for (int _=1;_<=m;_++) {
        int u,v; scanf("%d%d",&u,&v);
        if (u == v || g[u][v]) continue;
        e[u].push_back(v);
        e[v].push_back(u);
        g[u][v] = g[v][u] = 1;
    }

    for (int i=1;i<=n;i++) if (!match[i]) aug(i);

    int ans = 0;
    for (int i=1;i<=n;i++) if (match[i] > i) ans++;
    printf("%d\n",ans);
    for (int i=1;i<=n;i++) printf("%d%c",match[i],i==n?'\n':' ');
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值