https://vjudge.net/problem/URAL-1099
题意:给定inf组人,给定的两个人可以在一组工作,问最多可以有多少人一起工作,并输出分组情况
不能强行分成二分图的话,就是一般图匹配的模板题了
二分图是能够把图完全分成两部分的图,进行最大匹配的时候比较简单,一般图匹配的时候会出现奇圈
这个时候需要用到带花树算法(好听)进行一般图的最大匹配
并不完全理解原理,只是会用kuangbin巨巨的板子,改了改适合自己的风格,咸鱼也加油!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 250;
int n; // 顶点个数,从1 - N
bool g[maxn][maxn];
int match[maxn]; // 存每个点的匹配信息
bool inq[maxn], inp[maxn], inb[maxn];
int head, tail;
int q[maxn];
int start, finish;
int nbase;
int f[maxn], base[maxn];
int Count;//匹配数,匹配对数是Count/2
void push(int u)
{
q[tail] = u;
tail ++;
inq[u] = 1;
}
int pop()
{
int res = q[head];
head ++;
return res;
}
int fc(int u, int v)//FindCommonAncestor寻找公共祖先
{
memset(inp, 0, sizeof(inp));
while(1)
{
u = base[u];
inp[u] = 1;
if(u == start) break;
u = f[match[u]];
}
while(1)
{
v = base[v];
if(inp[v]) break;
v = f[match[v]];
}
return v;
}
void rt(int u)//ResetTrace重置标记
{
int v;
while(base[u] != nbase)
{
v = match[u];
inb[base[u]] = inb[base[v]] = 1;
u = f[v];
if(base[u] != nbase) f[u] = v;
}
}
void bc(int u, int v)//BloosomContract 花 传播
{
nbase = fc(u, v);
memset(inb , 0, sizeof(inb));
rt(u);
rt(v);
if(base[u] != nbase) f[u] = v;
if(base[v] != nbase) f[v] = u;
for(int tu = 1; tu <= n; tu ++)
{
if(inb[base[tu]])
{
base[tu] = nbase;
if(! inq[tu])
push(tu);
}
}
}
void fa()// FindAugmentingPath 寻找增广路
{
memset(inq, 0, sizeof(inq));
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i ++)
base[i] = i;
head = tail = 1;
push(start);
finish = 0;
while(head < tail)
{
int u = pop();
for(int v = 1; v <= n; v ++)
{
if(g[u][v] && (base[u] != base[v]) && (match[u] != v))
{
if((v == start) || ((match[v] > 0) && f[match[v]] > 0))
bc(u, v);
else if(f[v] == 0)
{
f[v] = u;
if(match[v] > 0)
push(match[v]);
else
{
finish = v;
return ;
}
}
}
}
}
}
void ap() // AugmentPath 增广路
{
int u, v, w;
u = finish;
while(u > 0)
{
v = f[u];
w = match[v];
match[v] = u;
match[u] = v;
u = w;
}
}
void ed() // Edmonds 进行匹配
{
memset(match, 0, sizeof(match));
for(int u = 1; u <= n; u ++)
{
if(match[u] == 0)
{
start = u;
fa();
if(finish > 0) ap();
}
}
}
int main()
{
int u, v;
memset(g, 0, sizeof(g));
scanf("%d", &n);
while(scanf("%d%d", &u, &v) == 2)
g[u][v] = g[v][u] = 1;
ed(); // 进行匹配
Count = 0;
for(int u = 1; u <= n; u ++)
if(match[u] > 0)
Count ++;
printf("%d\n", Count);
for(int u = 1; u <= n; u ++)
if(u < match[u])
printf("%d %d\n", u, match[u]);
return 0;
}