当前位置: 首页 > news >正文

UOJ-79 一般图的最大匹配(带花树模板求解)

#79. 一般图最大匹配

从前一个和谐的班级,所有人都是搞OI的。有  n n 个是男生,有  0 0 个是女生。男生编号分别为  1,,n 1,…,n

现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。

有若干个这样的条件:第  v v 个男生和第  u u 个男生愿意组成小组。

请问这个班级里最多产生多少个小组?

输入格式

第一行两个正整数, n,m n,m。保证  n2 n≥2

接下来  m m 行,每行两个整数  v,u v,u 表示第  v v 个男生和第  u u 个男生愿意组成小组。保证  1v,un 1≤v,u≤n,保证  vu v≠u,保证同一个条件不会出现两次。

输出格式

第一行一个整数,表示最多产生多少个小组。

接下来一行  n n 个整数,描述一组最优方案。第  v v 个整数表示  v v 号男生所在小组的另一个男生的编号。如果  v v 号男生没有小组请输出  0 0


模板代码:

#include <algorithm>
#include <string.h>
#include <cstdio>
using namespace std;
const int maxn = 505;
const int maxm = 124755*2;
struct node{int v, next;} edge[maxm];
int no, head[maxn];
int n, m;
int match[maxn];
int pre[maxn];	//记录增广路中非匹配边
int mk[maxn], f[maxn];	//mk记录当前点是哪种类型: -1(未访问过),0(S型),1(T型)
int front, tail, q[maxn];	//模拟队列
int TIM, vis[maxn];	//对于lca的标记及时间轴
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
}
inline void add(int u, int v)
{
	edge[no].v = v, edge[no].next = head[u];
	head[u] = no++;
}
int getf(int x) {return x == f[x]? x: f[x]=getf(f[x]);}
int lca(int u, int v)	//巧妙地求法
{
	++TIM;
	while(vis[u] != TIM)
	{
		if(u != 0)
		{
			u = getf(u);	//花根
			if(vis[u] == TIM) return u;
			vis[u] = TIM;
			if(match[u] != -1) u = getf(pre[match[u]]);	
			//每一个S点的配偶(也就是T点)的pre 都是指向它的父亲的,于是就直接这么跳就可以
			else u = 0;
			//必须要到花根再进行操作,因为只有花根的pre才只想该花真正的父亲
		}
		swap(u, v);
	}
	return u;
}
void change(int u, int v, int _lca)	//缩花,将花上的所有点通过并查集缩为一点 
{
	while(getf(u) != _lca)
	{
		pre[u] = v;
		int t = match[u];
		mk[t] = 0;
		q[tail++] = t;
		if(tail >= maxn) tail = 1;
		if(getf(t) == t) f[t] = _lca;
		if(getf(u) == u) f[u] = _lca;
		v = t;
		u = pre[v];
	} 
}
bool bfs(int X)	//寻找增广路
{
	for(int i = 1; i <= n; ++i)
	f[i] = i, mk[i] = -1;
	front = tail = 1;
	q[tail++] = X, mk[X] = 0;
	while(front < tail)
	{
		int u = q[front];
		for(int k = head[u]; k+1; k = edge[k].next)
		{
			int v = edge[k].v;
			if(match[v] == -1 && v != X)
			//当且仅当v没被匹配且不为X
			{
				pre[v] = u;
				int t, las, now = v;
				//将增广路上的匹配边->未匹配边,未匹配边->匹配边
				while(now != -1)
				{
					t = pre[now];
					las = match[t];
					match[t] = now, match[now] = t;
					now = las;
				}
				return true;
			}
			if(mk[v] == -1)	//找到未访问的点,继续扩展
			{
				mk[v] = 1;
				pre[v] = u;
				mk[match[v]] = 0;
				q[tail++] = match[v];
				if(tail >= maxn) tail = 1;
			}
			else if(mk[v] == 0 && getf(u) != getf(v))	//遇到奇环,且之前未缩花
			{
				int _lca = lca(u, v);
				change(u, v, _lca);
				change(v, u, _lca);
			}
		}
		++front;
		if(front >= maxn) front = 1;	//模拟循环链表
	}
	return false;
}
void work()
{
	memset(match, -1, sizeof match);
	int ans = 0; TIM = 0;
	for(int i = 1; i <= n; ++i)
	if(match[i] == -1 && bfs(i))
	++ans;
	printf("%d\n", ans);
	for(int i = 1; i <= n; ++i)
	printf("%d%c", match[i]==-1? 0: match[i], i==n? '\n': ' ');
}
int main()
{
	while(~scanf("%d %d", &n, &m))
	{
		init();
		for(int i = 1; i <= m; ++i)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			add(u, v); add(v, u);
		}
		work();
	}
	return 0;
}


学自博文:

http://blog.csdn.net/qq_36797743/article/details/60968291

http://fanhq666.blog.163.com/blog/static/8194342620120304463580/

相关文章:

  • POJ-2823 POJ-3250 (单调队列 单调栈)
  • 关于量价十八则的口诀
  • HDU-3478 Catch(二分图染色+并查集)
  • RSA密钥的生成与配置
  • POJ 2536 Gopher II
  • HDU-1043 Eight(经典八数码问题, A*+康拓+曼哈顿距离+逆序数判断可解性、双向搜索)
  • codeforces-510E Fox And Dinner(带限制的二分图多重匹配+奇偶建图+打印路径)
  • C-Cleaning Pipes(判断两线段相交+二分图判定) 2015-2016 Northwestern European Regional Contest (NWERC 2015)
  • eclipse the user operation is waiting for building workspace to complete
  • 2-SAT 题目整理
  • 64位windows2003 未在本地计算机上注册 microsoft.jet.oledb.4.0 提供程序
  • HDU-5950 Recursive sequence(矩阵乘法)
  • “互联网+”引发IT人才招工荒-新华网安徽频道
  • Java从文件读入以及读出至文件
  • HDU-5963 朋友(树上博弈)
  • AHK 中 = 和 == 等比较运算符的用法
  • Android 控件背景颜色处理
  • avalon2.2的VM生成过程
  • CentOS7简单部署NFS
  • CSS 三角实现
  • Druid 在有赞的实践
  • input的行数自动增减
  • Java读取Properties文件的六种方法
  • Laravel 中的一个后期静态绑定
  • PHP 小技巧
  • Vue组件定义
  • 前端临床手札——文件上传
  • 使用API自动生成工具优化前端工作流
  • 小而合理的前端理论:rscss和rsjs
  • 译自由幺半群
  • 在Unity中实现一个简单的消息管理器
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • #include<初见C语言之指针(5)>
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (06)Hive——正则表达式
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (java)关于Thread的挂起和恢复
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二)windows配置JDK环境
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (九)c52学习之旅-定时器
  • (力扣)1314.矩阵区域和
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (一) springboot详细介绍
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .axf 转化 .bin文件 的方法
  • .gitignore
  • .net core 控制台应用程序读取配置文件app.config
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .Net Redis的秒杀Dome和异步执行
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)