URAL 1099 Work Scheduling(一般图匹配模板)

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <stack>
#include <queue>
#include <map>
#include <vector>
#include <cstdlib>
#include <set>
using namespace std;

#define LL long long
#define N 520
#define M 400020
#define eps 1e-8
#define MP make_pair
#define Pi acos(-1.0)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define inf 0x3f3f3f3f
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define mod 1000000007

struct graph {
	int n, match[N];
	bool adj[N][N];

	void clear(int nn = 0) {
		n = nn;
		memset(adj, 0, sizeof adj);
	}

	void add(int u, int v) {
		adj[u][v] = adj[v][u] = 1;
	}

	int gao() {
		memset(match, -1, sizeof match);
		int ans = 0;
		for(int i = 1; i <= n; ++i) {
			if(match[i] == -1)
				ans += bfs(i);
		}
		return ans;
	}

	int q[N], pre[N], base[N];
	bool inq[N], inblossom[N];

	int bfs(int p) {
		memset(pre, -1, sizeof pre);
		memset(inq, 0, sizeof inq);
		for(int i = 1; i <= n; ++i) base[i] = i;

		q[0] = p;
		inq[p] = 1;
		for(int s = 0, t = 1; s < t; ++s) {
			int u = q[s];
			for(int v = 1; v <= n; ++v) {
				if(adj[u][v] && base[u] != base[v] && v != match[u]) {
					if(v == p || (match[v] != -1 && pre[match[v]] != -1)) {
						int b = contract(u, v);
						for(int i = 1; i <= n; ++i) {
							if(inblossom[base[i]]) {
								base[i] = b;
								if(inq[i] == 0) {
									inq[i] = 1;
									q[t++] = i;
								}
							}
						}
					}
					else if(pre[v] == -1) {
						pre[v] = u;
						if(match[v] == -1) {
							aug(v);
							return 1;
						}
						else {
							q[t++] = match[v];
							inq[match[v]] = 1;
						}
					}
				}
			}
		}
		return 0;
	}
	void aug(int u) {
		while(u != -1) {
			int v = pre[u];
			int k = match[v];
			match[u] = v;
			match[v] = u;
			u = k;
		}
	}
	void change_blossom(int b, int u) {
		while(base[u] != b) {
			int v = match[u];
			inblossom[base[v]] = inblossom[base[u]] = 1;
			u = pre[v];
			if(base[u] != b) {
				pre[u] = v;
			}
		}
	}
	int contract(int u, int v) {
		memset(inblossom, 0, sizeof inblossom);
		int b = lca(base[u], base[v]);
		change_blossom(b, u);
		change_blossom(b, v);
		if(base[u] != b) {
			pre[u] = v;
		}
		if(base[v] != b)
			pre[v] = u;
		return b;
	}
	int lca(int u, int v) {
		bool in_path[N];
		memset(in_path, 0, sizeof in_path);
		while(1) {
			in_path[u] = 1;
			if(match[u] == -1) break;
			u = base[pre[match[u]]];
		}

		while(!in_path[v]) {
			v = base[pre[match[v]]];
		}
		return v;
	}
}g;

int n;

int main() {
	scanf("%d", &n);
	g.clear(n);
	int x, y;
	while(scanf("%d%d", &x, &y) != EOF) {
		g.add(x, y);
	}
	bool mark[N];

	memset(mark, 0, sizeof mark);
	int ans = g.gao();
	printf("%d\n", ans * 2);

	for(int i = 1; i <= n; ++i) {
		if(g.match[i] != -1 && mark[i] == 0 && mark[g.match[i]] == 0) {
			printf("%d %d\n", i, g.match[i]);
			mark[i] = mark[g.match[i]] = 1;
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值