URAL 1099 Work Scheduling (一般图最大匹配带花树)

版权声明:get busy living...or get busy dying https://blog.csdn.net/qq_41444888/article/details/89258050

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;
}

猜你喜欢

转载自blog.csdn.net/qq_41444888/article/details/89258050