UOJ79 一般图最大匹配
题目描述
从前一个和谐的班级,所有人都是搞OI的。有 nn 个是男生,有 00 个是女生。男生编号分别为 1,…,n1,…,n。
现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。
有若干个这样的条件:第 vv 个男生和第 uu 个男生愿意组成小组。
请问这个班级里最多产生多少个小组?
输入格式
第一行两个正整数,n,mn,m。保证 n≥2n≥2。
接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个男生愿意组成小组。保证 1≤v,u≤n1≤v,u≤n,保证 v≠uv≠u,保证同一个条件不会出现两次。
输出格式
第一行一个整数,表示最多产生多少个小组。
接下来一行 nn 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生所在小组的另一个男生的编号。如果 vv 号男生没有小组请输出 00。
样例一
input
10 20
9 2
7 6
10 8
3 9
1 10
7 1
10 9
8 6
8 2
8 1
3 1
7 5
4 7
5 9
7 8
10 4
9 1
4 8
6 3
2 5
output
5
9 5 6 10 2 3 8 7 1 4
样例二
input
5 4
1 5
4 2
2 1
4 3
output
2
2 1 4 3 0
正解:带花树算法
解题报告:
这道题是一般图最大匹配,也就是带花树算法裸题。
大概讲一下一般图最大匹配的思想:一般图最大匹配由带花树算法实现,2015年国家集训队论文中我校学长陈胤伯详细介绍了这一算法。
考虑一般图与二分图最大的不同就在于一般图存在奇环,所以我们不能完全套用二分图最大匹配的算法。
在这里不加以证明的给出具体做法(证明详见2015年国家队论文):
每次从一个未盖点出发,将其命名为偶点(偶点匹配的点称之为奇点),枚举其出边以及出边连接的点v:
如果v在本次BFS中还未被经过,则假设未匹配,那么找到了一条增广路,原路返回,把原来的匹配边和非匹配边取反,这样可以使答案加一;否则,将v的匹配点加入队列中拓展,根据我们上面的定义,v的匹配点显然也是偶点。
如果v已经访问过,那么显然出现了环,这个环如果是偶环则不用考虑,如果是奇环且本身两个点就不处在同一个现有已经处理过的奇环中,我们就需要将其缩为一个点(或者说是一朵花),并且把上面的奇点全都标记为偶点,丢到队列里面拓展。
这就是带花树的完整做法。不理解的可以结合我的代码理解一下。我就是看别人代码看懂的......
代码如下:
//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 520;
const int MAXM = 250011;
const int MAXL = 10011;
int n,m,ecnt,first[MAXN],next[MAXM],to[MAXM],father[MAXN],Tim;
int dui[MAXL],head,tail,id[MAXN],pre[MAXN],match[MAXN],ans,vis[MAXN];
inline int find(int x){ if(father[x]!=x) father[x]=find(father[x]); return father[x]; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline int lca(int x,int y){
Tim++;
while(vis[x]!=Tim) {
if(x) {
x=find(x);
if(vis[x]==Tim) return x;
vis[x]=Tim;
if(match[x]!=0) x=find(pre[match[x]]);
else x=0;
}
swap(x,y);
}
return x;
} inline 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; dui[++tail]=z; }
if(find(z)==z) father[z]=k;
if(find(x)==x) father[x]=k;
y=z; x=pre[y];
}
} inline bool bfs(int ini){
for(int i=1;i<=n;i++) id[i]=-1,father[i]=i;
head=tail=0; dui[++tail]=ini; id[ini]=0; int u;
while(head<tail) {
u=dui[++head];
for(int i=first[u];i;i=next[i]) {
int v=to[i];
if(id[v]==-1) {
pre[v]=u; id[v]=1;
if(!match[v]) {
int last,t,now=v;
while(now!=0) {
t=pre[now]; last=match[t];
match[t]=now; match[now]=t;
now=last;
}
return true;
}
id[match[v]]=0; dui[++tail]=match[v];
}
else if(id[v]==0&&find(u)!=find(v)){ //出现奇环且不是在同一个环中
int g=lca(u,v);
change(u,v,g);
change(v,u,g);
}
}
}
return false;
} inline void work(){
n=getint(); m=getint(); int x,y;
for(int i=1;i<=m;i++) {
x=getint(); y=getint();
next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
}
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]);
} int main()
{
work();
return 0;
}
UOJ79 一般图最大匹配的更多相关文章
- 【题解】Uoj79一般图最大匹配
带花树裸题,感觉带花树强强……不会的勿看此文,解释的可能不对,只是给自己看的!!!如题,带花树即为求一般图最大匹配算法(匈牙利与dinic为二分图最大匹配).推荐论文:2015年<浅谈图的匹配算 ...
- [转]带花树,Edmonds's matching algorithm,一般图最大匹配
看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...
- HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力
一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...
- 【Learning】带花树——一般图最大匹配
一般图最大匹配--带花树 问题 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. 这个问题的退化版本就是二分图最大匹配. 由于二分图中不存在奇环,偶环对最大匹配并无 ...
- HDU 4687 Boke and Tsukkomi (一般图最大匹配)【带花树】
<题目链接> 题目大意: 给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的. 解题分析: 所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义.那怎样 ...
- 【UOJ#79】一般图最大匹配(带花树)
[UOJ#79]一般图最大匹配(带花树) 题面 UOJ 题解 带花树模板题 关于带花树的详细内容 #include<iostream> #include<cstdio> #in ...
- ZOJ 3316 Game 一般图最大匹配带花树
一般图最大匹配带花树: 建图后,计算最大匹配数. 假设有一个联通块不是完美匹配,先手就能够走那个没被匹配到的点.后手不论怎么走,都必定走到一个被匹配的点上.先手就能够顺着这个交错路走下去,最后一定是后 ...
- [一般图最大匹配]Bimatching
10566 Bimatching 题意:一个男生必须跟两个女生匹配,求最大匹配 思路:一般的二分图匹配做不了,网络流也不会建图,这题采用的是一般图匹配 首先在原来二分图的基础上,将一个男生拆成两个点 ...
- [WC2016]挑战NPC(一般图最大匹配)
[WC2016]挑战NPC(一般图最大匹配) Luogu 题解时间 思路十分有趣. 考虑一个筐只有不多于一个球才有1的贡献代表什么. 很明显等效于有至少两个位置没有被匹配时有1的贡献. 进而可以构造如 ...
随机推荐
- RESTful Api 身份认证安全性设计
REST是一种软件架构风格.RESTful Api 是基于 HTTP 协议的 Api,是无状态传输.它的核心是将所有的 Api 都理解为一个网络资源.将所有的客户端和服务器的状态转移(动作)封装到 H ...
- js通过循环多张图片实现动画效果
以小鱼摇尾巴和眨眼睛为例 动画思路: 1.将图片资源放在数组里面 2.通过计时器来设定间隔时间 3.通过计数器来取相应的图片 第一步:基本框架,鱼身体 <body> <canvas ...
- 【HTML5&CSS3进阶03】Jser与Csser如何一起愉快的翻新老组件
上次,我们形成了两种header的布局,一种flexbox,一种float,最后与身边做重构的同事交流下来,选择了float的布局. 事实上布局的选型不需要我关注,我的参与或者一些意见多数是自我提升, ...
- SVG图形引用、裁切、蒙版
SVG图形引用.裁切.蒙版,使用三个标签: 1. <use>标签创建图形引用 2. <clipPath>标签裁切图形 3. <mask>标签创建蒙版 ...
- SlidingMenu 侧滑菜单的用法
很多APP都有侧滑菜单的功能,部分APP左右都是侧滑菜单~SlidingMenu 这个开源项目可以很好帮助我们实现侧滑功能,将侧滑菜单引入项目的方式很多中,先通过例子介绍各种引入方式,然后给大家展示个 ...
- SVN使用_获取某版本后改动的文件列表
本章将讲解如何通过svn命令获取某版本后改动的所有文件 一键操作,告别svn log的繁杂对比工作. 1:安装SVN命令行工具Subversion(不是TortoiseSVN) 下载Subversio ...
- 高性能Mysql主从架构的复制原理及配置详解
温习<高性能MySQL>的复制篇. 1 复制概述 Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台 ...
- hadoop-2.7.1伪分布环境搭建
1.准备Linux环境 1.0 点击VMware快捷方式,右键打开文件所在位置 -> 双击vmnetcfg.exe -> VMnet1 host-only ->修改subnet i ...
- CSS3:linear-gradient,线性渐变的使用方法
CSS3 渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳的过渡. 以前,你必须使用图像来实现这些效果,现在通过使用 CSS3 的渐变(gradients)即可实现.此外,渐变效果 ...
- 开发管理系统时,安装sqlserver2005问题整理
最近在为单位开发一个综合管理系统.但是由于时间的问题,有时候就把程序带回家进行修改.但是家里有没有环境,就把数据库文件和程序带回家,可是随之问题来了.要重新在家里陪着开发环境,vs2008非常快的就安 ...