Editorial for Fast Maximum Matching


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Lưu ý: Các code mẫu dưới đây chỉ mang tính tham khảo và có thể không AC được bài tập này

Code mẫu của flashmt

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

struct HopcroftKarp
{
    vector <int> leftMatch, rightMatch, dist, cur;
    vector < vector <int> > a;
    int m, n;

    HopcroftKarp() {}
    HopcroftKarp(int _m, int _n)
    {
        m = _m; n = _n;
        a = vector < vector <int> >(m);
        leftMatch = vector <int>(n, -1);
        rightMatch = vector <int>(m, -1);
        dist = vector <int>(m, -1);
        cur = vector <int>(m, -1);
    }

    void addEdge(int x, int y)
    {
        a[x].push_back(y);
    }

    int bfs()
    {
        int found = 0;
        queue <int> q;
        for (int i = 0; i < m; i++)
            if (rightMatch[i] < 0) dist[i] = 0, q.push(i);
            else dist[i] = -1;

        while (!q.empty())
        {
            int x = q.front(); q.pop();
            for (int i = 0; i < int(a[x].size()); i++)
            {
                int y = a[x][i];
                if (leftMatch[y] < 0) found = 1;
                else 
                    if (dist[leftMatch[y]] < 0)
                        dist[leftMatch[y]] = dist[x] + 1, q.push(leftMatch[y]);
            }
        }

        return found;
    }

    int dfs(int x)
    {
        for (; cur[x] < int(a[x].size()); cur[x]++)
        {
            int y = a[x][cur[x]];
            if (leftMatch[y] < 0 || (dist[leftMatch[y]] == dist[x] + 1 && dfs(leftMatch[y])))
            {
                leftMatch[y] = x; rightMatch[x] = y;
                return 1;
            }
        }
        return 0;
    }

    int maxMatching()
    {
        int match = 0;
        while (bfs())
        {
            for (int i = 0; i < m; i++) cur[i] = 0;
            for (int i = 0; i < m; i++) 
                if (rightMatch[i] < 0) match += dfs(i);
        }
        return match;
    }
};

int main()
{
    int m, n, edge, x, y;
    cin >> m >> n >> edge;
    HopcroftKarp u(m, n);
    while (edge--) scanf("%d%d", &x, &y), u.addEdge(--x, --y);
    cout << u.maxMatching() << endl;
}

Code mẫu của happyboy99x

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

const int N = 50000, INF = 1e9;
int mx[N], my[N], d[N], nx, ny;
vector<int> g[N];

void enter() {
    int m; cin >> nx >> ny >> m;
    for(int i = 0; i < m; ++i) {
        int u, v; cin >> u >> v;
        g[u-1].push_back(v-1);
    }
}

bool dfs(int u, int mind) {
    for (int v : g[u]) if(my[v] == -1 ? d[u] == mind : d[my[v]] == d[u]+1 && dfs(my[v], mind)) return mx[u] = v, my[v] = u, true;
    d[u] = INF;
    return false;
}

int maxMatch() {
    int matching = 0;
    fill(mx, mx + nx, -1); fill(my, my + ny, -1);
    while(true) {
        fill(d, d + nx, INF); queue<int> q;
        for(int u = 0; u < nx; ++u) if(mx[u] == -1) d[u] = 0, q.push(u);
        int mind = INF;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for (int v : g[u]) if(my[v] == -1) mind = min(mind, d[u]);
            else if(d[my[v]] == INF) d[my[v]] = d[u]+1, q.push(my[v]);
        }
        if(mind == INF) break;
        for(int u = 0; u < nx; ++u) if(d[u] > mind) d[u] = INF;
        for(int u = 0; u < nx; ++u)
            if(mx[u] == -1 && dfs(u, mind)) ++matching;
    }
    return matching;
}

int main() {
    ios::sync_with_stdio(false);
    enter();
    cout << maxMatch() << endl;
    return 0;
}

Code mẫu của ladpro98

#include <bits/stdc++.h>

using namespace std;

struct BipartiteGraph {
    vector<vector<int> > E;
    vector<vector<pair<int, int> > > a;
    vector<int> match;
    vector<int> edgeMatch;
    vector<bool> was;
    int m, n;

    BipartiteGraph(int m, int n) {
        this->m = m; this->n = n;
        E.clear();
        a.clear();
        a.resize(m);
        match.assign(n, -1);
        edgeMatch.assign(n, -1);
        was.assign(n, false);
    }

    void addEdge(int u, int v, vector<int> expression) {
        int index = E.size();
        a[u].push_back(make_pair(v, index));
        E.push_back(expression);
    }

    bool dfs(int u) {
        for (int i = 0; i < a[u].size(); ++i) {
            int v = a[u][i].first;
            if (was[v]) continue;
            was[v] = true;
            if (match[v] == -1 || dfs(match[v])) {
                match[v] = u;
                edgeMatch[v] = a[u][i].second;
                return true;
            }
        }
        return false;
    }

    int fastMatch() {
        vector<int> buffer;
        for (int i = 0; i < m; ++i) buffer.push_back(i);
        bool stop = false;
        int ans = 0;
        do {
            stop = true;
            for (int i = 0; i < n; ++i) was[i] = false;
            for (int i = (int)buffer.size() - 1; i >= 0; --i) {
                int u = buffer[i];
                if (dfs(u)) {
                    ++ans;
                    stop = false;
                    buffer[i] = buffer.back();
                    buffer.pop_back();
                }
            }
        } while (!stop);
        return ans;
    }
};

int main() {
    ios::sync_with_stdio(false);
    int n, m, p; cin >> m >> n >> p;
    BipartiteGraph G(m, n);
    int u, v;
    while (p--) {
        cin >> u >> v;
        G.addEdge(--u, --v, vector<int>());
    }
    cout << G.fastMatch() << endl;
    return 0;
}

Code mẫu của RR

#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <complex>
#include <iostream>
#include <algorithm>

#include <ctime>
#include <deque>
#include <bitset>
#include <cctype>
#include <utility>
#include <cassert>

#define FOR(i,a,b) for(int i=(a),_b=(b); i<=_b; i++)
#define FORD(i,a,b) for(int i=(a),_b=(b); i>=_b; i--)
#define REP(i,a) for(int i=0,_a=(a); i<_a; i++)
#define EACH(it,a) for(__typeof(a.begin()) it = a.begin(); it != a.end(); ++it)

#define DEBUG(x) { cout << #x << " = "; cout << (x) << endl; }
#define PR(a,n) { cout << #a << " = "; FOR(_,1,n) cout << a[_] << ' '; cout << endl; }
#define PR0(a,n) { cout << #a << " = "; REP(_,n) cout << a[_] << ' '; cout << endl; }

#define sqr(x) ((x) * (x))
using namespace std;

// Index from 1
const int inf = 1000111;
struct Matching {
    int n;
    vector<int> matchL, matchR, dist;
    vector<bool> seen;
    vector< vector<int> > ke;

    Matching(int n) : n(n), matchL(n+1), matchR(n+1), dist(n+1), seen(n+1, false), ke(n+1) {}

    void addEdge(int u, int v) {
        ke[u].push_back(v);
    }

    bool bfs() {
        queue<int> qu;
        FOR(u,1,n) if (!matchL[u]) {
            dist[u] = 0;
            qu.push(u);
        } else dist[u] = inf;
        dist[0] = inf;

        while (!qu.empty()) {
            int u = qu.front(); qu.pop();
            for(__typeof(ke[u].begin()) v = ke[u].begin(); v != ke[u].end(); ++v) {
                if (dist[matchR[*v]] == inf) {
                    dist[matchR[*v]] = dist[u] + 1;
                    qu.push(matchR[*v]);
                }
            }
        }
        return dist[0] != inf;
    }

    bool dfs(int u) {
        if (u) {
            for(__typeof(ke[u].begin()) v = ke[u].begin(); v != ke[u].end(); ++v)
                if (dist[matchR[*v]] == dist[u] + 1 && dfs(matchR[*v])) {
                    matchL[u] = *v;
                    matchR[*v] = u;
                    return true;
                }
            dist[u] = inf;
            return false;
        }
        return true;
    }

    int match() {
        int res = 0;
        while (bfs()) {
            FOR(u,1,n)
                if (!matchL[u])
                    if (dfs(u)) ++res;
        }
        return res;
    }
};


int main() {
    ios :: sync_with_stdio(false); cin.tie(NULL);
    int m, n, p;
    while (cin >> m >> n >> p) {
        Matching match(max(m, n));
        while (p--) {
            int u, v; cin >> u >> v;
            match.addEdge(u, v);
        }
        cout << match.match() << endl;
    }
}

Code mẫu của hieult

#include<cstdio>
#include<cmath>
#include<math.h>
#include<cstring>
#include<cstdlib>
#include<cassert>
#include<ctime>
#include<algorithm>
#include<iterator>
#include<iostream>
#include<cctype>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<list>
#define fi first
#define se second
#define PB push_back
#define MP make_pair
#define ep 0.00001
#define oo 111111111
#define mod 1000000007
#define TR(c, it) for(typeof((c).begin()) it=(c).begin(); it!=(c).end(); it++)
#define rep(i, n) for(int i = 0; i < n; i++)
#define FOR(i, a, b) for(int i = a; i <= b; i++)
#define FORD(i, a, b) for(int i = a; i >= b; i--)
//#define g 9.81
double const PI=4*atan(1.0);

using namespace std;

typedef pair<int, int> II;
typedef vector<int> VI;
typedef vector<II> VII;
typedef vector<VI> VVI;
typedef vector<VII> VVII;
typedef long long ll;

void OPEN(){
    freopen("A.in","r",stdin);
    freopen("A.out","w",stdout);
}
// Dinic

#define maxn 50011
#define maxe 150111

struct HopcroftKarp{
    int nx, ny, E, adj[maxe], next[maxe], last[maxn],
    matx[maxn], maty[maxn], que[maxn], level[maxn], run[maxn];

    void init(int _nx, int _ny){
        nx = _nx; ny = _ny; E = 0;
        FOR(x, 1, nx) last[x] = -1, matx[x] = -1;
        FOR(y, 1, ny) maty[y] = -1;
    }

    void add(int x, int y){
        adj[E] = y; next[E] = last[x]; last[x] = E++;
    }

    bool bfs(){
        bool found = false;
        int size = 0;
        FOR(x, 1, nx){
            if(matx[x] != -1) level[x] = -1;
            else{
                level[x] = 0;
                que[size++] = x;
            } 
        }

        rep(i, size){
            for(int x = que[i], e = last[x]; e != -1; e = next[e]){
                int y = adj[e];
                if(maty[y] == -1) found = true;
                else if(level[maty[y]] == -1){
                    level[maty[y]] = level[x] + 1;
                    que[size++] = maty[y];
                }
            }
        }

        return found;
    }

    int dfs(int x){
        for(int &e = run[x]; e != -1; e = next[e]){
            int y = adj[e];
            if(maty[y] == -1 || (level[maty[y]] == level[x] + 1 && dfs(maty[y]))){
                maty[y] = x;
                matx[x] = y;
                return 1;
            }
        }
        return 0;
    }

    int maxMatching(){
        int total = 0;
        while(bfs()){
            FOR(x, 1, nx) run[x] = last[x];
            FOR(x, 1, nx) if(matx[x] == -1) total += dfs(x);
        }
        return total;
    }
} hopkarp;

int main(){
   // OPEN();
    int n, m, k, u, v;
    scanf("%d %d %d", &n, &m, &k);
    hopkarp.init(n, m);
    rep(i, k){
        scanf("%d %d", &u, &v);
        hopkarp.add(u, v);
    }
    printf("%d", hopkarp.maxMatching());
}

Code mẫu của skyvn97

#include<cstdio>
#include<vector>
#include<queue>
#define MAX   50505
using namespace std;
const int INF=(int)1e7;
vector<int> g[MAX];
int matx[MAX];
int maty[MAX];
int d[MAX];
int m,n,p;
void loadgraph(void) {
    scanf("%d",&m);
    scanf("%d",&n);
    scanf("%d",&p);
    int i,u,v;
    for (i=1;i<=p;i=i+1) {
        scanf("%d",&u);
        scanf("%d",&v);
        g[u].push_back(v);
    }
}
bool BFS(void) {
    queue<int> q;
    while (!q.empty()) q.pop();
    int i,u,v;
    for (i=1;i<=m;i=i+1) {
        if (matx[i]==0) {
            d[i]=0;
            q.push(i);
        }
        else d[i]=INF;
    }
    d[0]=INF;
    while (!q.empty()) {
        u=q.front();q.pop();
        if (d[u]<d[0])
            for (i=0;i<g[u].size();i=i+1) {
                v=g[u][i];
                if (d[maty[v]]>=INF) {
                    d[maty[v]]=d[u]+1;
                    q.push(maty[v]);
                }
            }
    }
    return (d[0]<INF);
}
bool DFS(const int &u) {
    if (u==0) return (true);
    int i,v;
    for (i=0;i<g[u].size();i=i+1) {
        v=g[u][i];
        if (d[maty[v]]==d[u]+1)
            if (DFS(maty[v])) {
                matx[u]=v;
                maty[v]=u;
                return (true);
            }       
    }
    d[u]=INF;
    return (false);
}
void fastmatching(void) {
    int i;
    for (i=1;i<=m;i=i+1) matx[i]=0;
    for (i=1;i<=n;i=i+1) maty[i]=0;
    int res=0;
    while (BFS()) {
    //  printf("ok\n");
        for (i=1;i<=m;i=i+1)
            if (matx[i]==0)
                if (DFS(i)) res++;
        //printf("%d\n",res);
    }
    printf("%d",res);
}
int main(void) {
#ifndef ONLINE_JUDGE
    freopen("tmp.txt","r",stdin);
#endif
    loadgraph();
    fastmatching();
    return 0;
}

Code mẫu của khuc_tuan

#include <cstdio>
#include <cstring>
using namespace std;

struct List {
    int i;
    List * next;    
};

List cont[400000];
int ncont1, ncont2;

List * ke[50050];
List * keY[50050];

int M, N, nE;
int X[50050], Y[50050], Q[50050], levelX[50050], levelY[50050];
bool vs[50050];
int L, R, maxLevel, socap;

inline void addList( List * & p, int i, int & cn) {
    List * q = cont + ++cn;
    q->i = i;
    q->next = p;
    p = q;
}

bool bfs() {
    L = 1;
    R = 0;
    memset( levelX, 0, sizeof(levelX));
    memset( levelY, 0, sizeof(levelY));
    ncont2 = 155000;
    memset( keY, 0, sizeof(keY));

    for(int i=1;i<=M;++i) if(X[i]==0) Q[++R] = i, levelX[i] = 1;
    maxLevel = 1000000;
    while(L<=R) {
        int u = Q[L++];
        if(levelX[u] > maxLevel) break;
        for(List * p = ke[u]; p!=NULL; p = p->next) {
            int v = p->i;
            if(levelY[v]==0) {
                levelY[v] = levelX[u] + 1;
                if(Y[v]==0)
                    maxLevel = levelY[v];
                else 
                    if(levelX[Y[v]]==0) {
                        levelX[Y[v]] = levelY[v] + 1;
                        Q[++R] = Y[v];
                    }
            }
            if(levelY[v] == levelX[u] + 1) addList( keY[v], u, ncont2);
        }
    }
    return maxLevel < 1000000;
}

bool dfs(int j) {
    for(List * p = keY[j]; p!=NULL; p = p->next) {
        int i = p->i;
        if(!vs[i]) {
            vs[i] = true;
            if(levelX[i]==1 || dfs(X[i])) {
                X[i] = j;
                Y[j] = i;
                return true;
            }
        }
    }
    return false;
}

void tang() {
    memset( vs, 0, sizeof(vs));
    for(int i=1;i<=N;++i) 
        if(levelY[i]==maxLevel && Y[i]==0)
            if(dfs(i)) ++socap;
}

int main() {
    scanf("%d%d%d", &M, &N, &nE);
    for(int i=0;i<nE;++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        if(X[u]==0 && Y[v]==0) {
            X[u] = v;
            Y[v] = u;
            ++socap;
        }
        addList( ke[u], v, ncont1);
    }   
    while(bfs()) tang();
    printf("%d\n", socap);
    return 0;
}

Comments

Please read the guidelines before commenting.


There are no comments at the moment.