【题解】Uoj79一般图最大匹配

  带花树裸题,感觉带花树强强……不会的勿看此文,解释的可能不对,只是给自己看的!!!如题,带花树即为求一般图最大匹配算法(匈牙利与dinic为二分图最大匹配)。推荐论文:2015年《浅谈图的匹配算法及其应用》(长郡中学    ——陈胤伯)。论文当中有对于带花树算法的详细解析,在这里只想记录一下算法的基本流程:

——————————————————————————

  \(id\) : 记录一个点为奇点/偶点(0偶1奇)。

  \(fa\) : 并查集记录一个点属于哪一个点为根的花。

——————————————————————————

  我们对于每一个没有匹配到的点进行 bfs,默认该点为一个偶点。

  当我们遍历到一个未访问过的点(在此次bfs中):

    -若该点未匹配:

    Yes!我们找到了一条新的增广路。顺着 \( pre \) 数组的指引反向增广,修改匹配的对象。(当前点为\(x\), \(y = pre[x]\),\(z = match[y]\), 则应使 \(x\), \(y\) 成为匹配边,\(z\) 点继续增广(过程同上,一直到增广不下去了为止))。

    -若该点已匹配:

    将它的匹配点标记为偶点,推进队列。

  遍历到一个访问过的点(在此次bfs中):

    -若该点是一个奇点:

    找到的是一个偶环,无视。

    -若该点是一个偶点:

    如果这两个点本来就在同一朵花中,无视。否则进行缩花。我们找到这两点在bfs树上的 lca: \(k\);将这两点之间连上边从\(x\) 开始向上遍历所有的匹配边,找到一朵花的根节点就修改其花根为 \(k\); 若找到的点有匹配点,则将匹配点也标记为偶点并压入队列。

  总之是个玄学算法……

#include <bits/stdc++.h>
using namespace std;
#define maxn 300000
int n, m, match[maxn];
int pre[maxn], id[maxn];
int timer, fa[maxn], ans;
int vis[maxn];
queue <int> q;

struct edge
{
    int cnp = 1, head[maxn], to[maxn], last[maxn];
    void add(int u, int v)
    {
        to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
        to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
    }
}E1;

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) k = -1; c = getchar(); }
    while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar();
    return x * k;
}

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

void Clear(queue<int> &q) {
    queue <int> empty;
    swap(empty, q);
}

int LCA(int x, int y)
{
    timer ++;
    while(vis[x] != timer)
    {
        if(x)
        {
            x = find(x);
            if(vis[x] == timer) return x;
            vis[x] = timer;
            if(match[x]) x = find(pre[match[x]]);
            else x = 0;
        }
        swap(x, y);
    }
    return x;
}

void Change(int x, int y, int k)
{
    while(find(x) != k)
    {
        pre[x] = y; int z = match[x];
        if(id[z] == 1) id[z] = 0, q.push(z);
        if(find(z) == z) fa[z] = k;
        if(find(x) == x) fa[x] = k;
        y = z; x = pre[y];
    }
}

bool bfs(int u)
{
    for(int i = 1; i <= n; i ++) id[i] = -1, fa[i] = i;
    Clear(q); q.push(u); id[u] = 0;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = E1.head[u]; i; i = E1.last[i])
        {
            int v = E1.to[i];
            if(id[v] == -1)
            {
                pre[v] = u; id[v] = 1;
                if(match[v])
                {
                    id[match[v]] = 0; q.push(match[v]);
                    continue;
                }
                int last, t, now = v;
                while(now)
                {
                    t = pre[now]; last = match[t];
                    match[t] = now, match[now] = t;
                    now = last;
                }
                return 1;
            }
            else if(!id[v] && find(u) != find(v))
            {
                int lca = LCA(u, v);
                Change(u, v, lca), Change(v, u, lca);
            }
        }
    }
    return 0;
}

int main()
{
    n = read(), m = read();
    for(int i = 1; i <= m; i ++)
    {
        int x = read(), y = read();
        E1.add(x, y);
    }
    for(int i = 1; i <= n; i ++) if(!match[i] && bfs(i)) ans ++;
    printf("%d\n", ans);
    for(int i = 1; i <= n; i ++) printf("%d ", match[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/twilight-sx/p/9244779.html

时间: 2024-11-13 06:59:12

【题解】Uoj79一般图最大匹配的相关文章

UOJ79 一般图最大匹配

题目描述 从前一个和谐的班级,所有人都是搞OI的.有 nn 个是男生,有 00 个是女生.男生编号分别为 1,-,n1,-,n. 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽.每个人至多属于一个小组. 有若干个这样的条件:第 vv 个男生和第 uu 个男生愿意组成小组. 请问这个班级里最多产生多少个小组? 输入格式 第一行两个正整数,n,mn,m.保证 n≥2n≥2. 接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个男生愿意组成小

HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力

一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 如果C2+2==C1则这条边再某个最大匹配中 Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 649    Accepted Submission(s): 202

最短路思想实现一般图最大匹配

考虑一下一般图和二分图的区别,无非就在于二分图可能出现长为奇数的环. 如何排除奇数环的影响??? 最短路 设一般图中每条可匹配边长为1,该次匹配起点为v. 根据最短路定理,我们可以知道,v在带花树上到任意一个终点(即未匹配的点)的最短距离一定为奇数,且路径上一定不存在环. 那么,用广搜的方法去贪最短路的时候,贪出来的第一条路(即最短路)一定不含环. 设[1,n]代表S型点,[n+1,2*n]代表T型点,dist[i]表示v到i的最短路上经过的点数. 设ance[i][j]表示i的dist值为j的

poj 3020 一般图最大匹配 带花树开花算法

题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w <= 10 思路: 最小边覆盖=|V|-最大匹配 一般图最大匹配,带花树开花算法 /*poj 3020 一般图最大匹配 带花树开花算法 题意: 给出一个h*w的图,每个点都是'o'或'*',最少要用多少个1*2的矩形才能把图中所有的'*'都覆盖掉. 限制: 1 <= h <= 40; 1 <= w &l

ZOJ 3316 Game 一般图最大匹配带花树

一般图最大匹配带花树: 建图后,计算最大匹配数. 如果有一个联通块不是完美匹配,先手就可以走那个没被匹配到的点,后手不论怎么走,都必然走到一个被匹配的点上,先手就可以顺着这个交错路走下去,最后一定是后手没有路可走,因为如果还有路可走,这一条交错路,就是一个增广路,必然有更大的匹配. Game Time Limit: 1 Second      Memory Limit: 32768 KB Fire and Lam are addicted to the game of Go recently.

[JZOJ5279]香港记者题解--最短路图

[JZOJ5279]香港记者题解--最短路图 题目链接 过 于 暴 力 分析 有一个naiive的想法就是从1到n跑最短路,中途建图,然后在图上按字典序最小走一遍,然而·这是不行的,你这样跳不一定能跳到终点. 所以应该是在1到n的最短路图上跳,怎么求有向图短路图?你跑一遍1到n得到\(dist1[]\),n到1的最短路得到\(dist[2]\),然后从1 BFS,对于原图一条\(u\),连向\(v\)的边,若\(dis1[u]+dis2[v]+dis(u,v)\)等于1到n的最短路距离,则最短路

UOJ #79 一般图最大匹配

一般图最大匹配 从前一个和谐的班级,所有人都是搞OI的.有 \(n\) 个是男生,有 \(0\) 个是女生.男生编号分别为 \(1,-,n\). 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽.每个人至多属于一个小组. 有若干个这样的条件:第 \(v\) 个男生和第 \(u\) 个男生愿意组成小组. 请问这个班级里最多产生多少个小组? 输入格式 第一行两个正整数,\(n,m\).保证 \(n≥2\). 接下来 \(m\) 行,每行两个整数 \(v,u\) 表示第

带花树——一般图最大匹配

问题 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. 这个问题的退化版本就是二分图最大匹配. 由于二分图中不存在奇环,偶环对最大匹配并无影响(可以调整).所以增广路算法是可以顺利应用的. 在一般图中,我们还是尝试使用BFS增广路的算法. 然而一般图中还会出现奇环,在寻找增广路的时候,怎么处理奇环上的冲突? 目的就是将奇环不断地缩起来(缩花),使得整个图在使用增广算法的时候不受影响,即不会经过奇环. ? ? ? 花 ? 一朵花由一个奇环缩点而成,一朵花里面可能还会有花.

一般图最大匹配带花树

参考博客:http://blog.sina.com.cn/s/blog_95ec9e7401018bga.html https://www.cnblogs.com/owenyu/p/6858508.html 用Dinic实现的二分图匹配的时间复杂度其实是O(M*N^0.5),这也许能够解释为什么一般网络流算法比Hungry要快了. 另外,带花树算法的正确性的证明比较困难:而其时间复杂度是可以做到O(M*N^0.5)的 简述一下“带花树”算法吧: 它的核心思想还是找增广路.假设已经匹配好了一堆点,