【UOJ】#79. 一般图最大匹配
题解
板子!我相信其实没人来看我的板子!但是为了防止我忘记,我还是要写点什么
我们考虑二分图,为什么二分图就能那么轻松地写出匹配的代码呢?因为匹配只会发生在黑点和白点之间,我们找寻增广路,必然是一黑一白一黑一白这么走
然而,一般图由于有了奇环,事情变得不妙了啊
奇环上的所有点,可以是……任意的奇偶性(起点到它的距离的奇偶性,可以是非简单路径)
那么我们就让任意奇偶性的点可以进行匹配就可以了,我们通过pre维护出一条路径到达根节点
怎么维护呢?缩花!
花?什么是花?
花就是奇环,我们找到花托(两个点的最近公共祖先),从两个点构建一条能走到花托的路径
如何构建
对于(u,v)和花托f
我们让u的pre走到v,然后令u跳到u匹配点的pre,v变成u的匹配点,继续这个操作,同时把这个匹配点改成偶点(可进行增广)
对v走到花托走到f进行类似的操作
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 505
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
struct node {
int to,next;
}E[MAXN * MAXN * 2];
int sumE,head[MAXN];
int N,M,fa[MAXN],pre[MAXN],matk[MAXN],sta[MAXN];
int Q[MAXN],L,R;
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
int getfa(int x) {
return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
int lca(int x,int y) {
static int vis[MAXN],Tim;
++Tim;
while(1) {//每个点都尝试走一步
x = getfa(x);
if(x) {
if(vis[x] == Tim) {
return x;
}
else vis[x] = Tim,x = pre[matk[x]];
}
swap(x,y);
}
}
void blossom(int u,int v,int flower_root) {
while(getfa(u) != flower_root) {
pre[u] = v;
//我们每个点既然都是奇偶难分(雾)
//就构建出一条这个点走到花托的交错路
//构建方法就是顺着匹配边往上跳
//这个时候我们碰到的匹配点还都以为自己是偶点= =(奇怪的叙述)
int m = matk[u];
if(sta[m] == 1) {sta[m] = 0;Q[++R] = m;}
//把所有以为自己是奇点的人告诉他们可以当偶点啦
if(u == fa[u]) fa[u] = flower_root;
if(m == fa[m]) fa[m] = flower_root;
v = m,u = pre[m];
}
}
bool match(int s) {
//sta : -1 未访问 0:偶点(起始点) 1:奇点
//pre : 交错树上的父亲,任意一点顺着当前自己的匹配点的pre会走到树根,也就是还原出了交错路
L = 1,R = 0;Q[++R] = s;
memset(sta,-1,sizeof(sta));
memset(pre,0,sizeof(pre));
sta[s] = 0;//起点是偶点
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
while(L <= R) {
int u = Q[L++];
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(sta[v] == -1) {
pre[v] = u;sta[v] = 1;
if(!matk[v]) {
for(int j = u , k = v,last; ; j = pre[k = last]) {
last = matk[j],matk[j] = k;matk[k] = j;
if(!last) break;
}//顺着pre节点找交错路,全部取反
return 1;
}
sta[matk[v]] = 0;
Q[++R] = matk[v];
}
else if(getfa(v) != getfa(u) && !sta[v]) {
int f = lca(u,v);blossom(u,v,f);blossom(v,u,f);
//两个偶点,缩花,两条路径爬到父亲
}
}
}
return 0;
}
void Init() {
read(N);read(M);
int u,v;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);
add(u,v);add(v,u);
}
}
void Solve() {
int ans = 0;
for(int i = 1 ; i <= N ; ++i) {
if(!matk[i] && match(i)) ++ans;
}
out(ans);enter;
for(int i = 1 ; i <= N ; ++i) {
out(matk[i]);
if(i == N) enter;
else space;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}
//5aaC5p6c5oiR5LiK5LiN5LqGdGh177yM5oiR5bCx5YaN5Lmf6KeB5LiN5Yiw54yr6ZSf5LqG
//4oCm4oCm54yr6ZSf55yf5Y+v54ix
【UOJ】#79. 一般图最大匹配的更多相关文章
- UOJ #79 一般图最大匹配 带花树
http://uoj.ac/problem/79 一般图和二分图的区别就是有奇环,带花树是在匈牙利算法的基础上对奇环进行缩点操作,复杂度似乎是O(mn)和匈牙利一样. 具体操作是一个一个点做类似匈牙利 ...
- UOJ #79. 一般图最大匹配
板子: #include<iostream> #include<cstdio> #include<algorithm> #include<vector> ...
- 【刷题】UOJ #79 一般图最大匹配
从前一个和谐的班级,所有人都是搞OI的.有 \(n\) 个是男生,有 \(0\) 个是女生.男生编号分别为 \(1,-,n\) . 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个 ...
- uoj#79. 一般图最大匹配(带花树)
传送门 带花树 不加证明的说一下过程好了:每次从一个未匹配点\(S\)出发bfs,设\(S\)为\(1\)类点,如果当前点\(v\)在本次bfs中未经过,分为以下两种情况 1.\(v\)是未匹配点,那 ...
- 【UOJ#79】一般图最大匹配(带花树)
[UOJ#79]一般图最大匹配(带花树) 题面 UOJ 题解 带花树模板题 关于带花树的详细内容 #include<iostream> #include<cstdio> #in ...
- UOJ79 一般图最大匹配
题目描述 从前一个和谐的班级,所有人都是搞OI的.有 nn 个是男生,有 00 个是女生.男生编号分别为 1,-,n1,-,n. 现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人 ...
- [转]带花树,Edmonds's matching algorithm,一般图最大匹配
看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...
- HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力
一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...
- 【Learning】带花树——一般图最大匹配
一般图最大匹配--带花树 问题 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. 这个问题的退化版本就是二分图最大匹配. 由于二分图中不存在奇环,偶环对最大匹配并无 ...
随机推荐
- codeforces gym101243 A C D E F G H J
gym101243 A #include<iostream> #include<cstdio> #include<cmath> #include<cstrin ...
- UESTC--1727
原题链接:http://acm.uestc.edu.cn/problem.php?pid=1727 分析:用 l[i] 记录第 i 层楼有多少物品需要往上继续搬运,如果某层楼没有物品,但是更上面还有, ...
- 超越icon font
很久以前,我们如何使用图标? 1.切图 2.拼合(Sprites) 原始社会啊! 后来CSSGagagrunt-css-sprite 字体图标 相见不曾相识 Emoji绘文字 iconfont.cn直 ...
- java学习——equals()和==的比较
equals 方法是 java.lang.Object 类的方法. 下面从两个方面来说明equals()和==的差别:(1)对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比 ...
- [oracle]centos 7 安装oracle
换了好几个系统终于还是利用centos安装oralce成功了,这里我也参考了网上的好多资料以及oracle的官方文档 1.下载oracle,我这里选择的是11gr2版本,下载下来后有两个文件,利用un ...
- HDU 1034 Candy Sharing Game (模拟)
题目链接 Problem Description A number of students sit in a circle facing their teacher in the center. Ea ...
- MyBatis数据库字段和实体对象属性名不一致的解决方案
数据库和对象的属性名不一致是很常见的问题,这个时候依从表字段到对象属性名的按名称匹配映射已经搞不定这个了,下面是几种解决方案. 1. 开启驼峰转换 如果数据库中的字段名与对象只是简单的不一致的话,比如 ...
- ASP.NET MVC EF直接更新数据(不需查询)
EF(EntityFrameWork) ORM(对象关系映射框架/数据持久化框架),根据实体对象操作数据表中数据的一种面向对象的操作框架,底层也是调用ADO.NET ASP.NET MVC 项目会自动 ...
- html5手机Web单页应用实践--起点移动阅读
一开始以hybrid形式做了一个android的小说阅读客户端,叫4G阅读.而后由于业务需求,要迅速实现纯手机html5 版的,所以就直接在原先客户端内内嵌的网页进行改版,快速实现以后在优化的过程中发 ...
- javac -cp java -cp
///////////////////////////////////////////////////////////////////////////////////// 编译java文件的命令都知道 ...