【UOJ 79】 一般图最大匹配 (?带花树开花)

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

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

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

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

输入格式

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

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

输出格式

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

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

样例一

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

限制与约定

1≤n≤500,1≤m≤124750

时间限制:1s

空间限制:256MB

【分析】

  推荐博客:http://blog.csdn.net/yihuikang/article/details/10460997

  http://blog.csdn.net/jackyguo1992/article/details/11271497

上模板:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 510
#define Maxm 1247501+100 

int n;

struct node
{
	int x,y,next;
}t[Maxm*2];
int first[Maxn],len;

void ins(int x,int y)
{
	t[++len].x=x;t[len].y=y;
	t[len].next=first[x];first[x]=len;
}

int fa[Maxn],nt[Maxn],mark[Maxn],match[Maxn];
int vis[Maxn],nw;
int ffa(int x)
{
	if(fa[x]!=x) fa[x]=ffa(fa[x]);
	return fa[x];
}

int merge(int x,int y)
{
	fa[ffa(x)]=ffa(y);
}

queue<int > q;

//找环
int LCA(int x,int y)
{
	nw++;
	while(1)
	{
		if(x)
		{
			x=ffa(x);
			if(vis[x]==nw) return x;
			vis[x]=nw;
			if(match[x]) x=nt[match[x]];
			else x=0;
		}
		int tt=x;x=y;y=tt;
	}
}

//奇环缩点
void shrink(int x,int rt)
{
	while(x!=rt)
	{
		int y=match[x],z=nt[y];
		if(ffa(z)!=rt) nt[z]=y;
		if(mark[y]==2) {q.push(y);mark[y]=1;}
		if(mark[z]==2) {q.push(z);mark[z]=1;}
		merge(x,y);merge(y,z);
		x=z;
	}
}

void augment(int now)
{
	nw=0;
	for(int i=1;i<=n;i++)
		nt[i]=0,vis[i]=0,mark[i]=0,fa[i]=i;
	while(!q.empty()) q.pop();
	q.push(now);mark[now]=1;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		if(match[now]) return;//当前搜索节点找到增广路
		for(int i=first[x];i;i=t[i].next)
		{
			int y=t[i].y;
			if(match[x]==y||ffa(x)==ffa(y)) continue;
			if(mark[y]==2) continue;
			//奇环缩点
			if(mark[y]==1)
			{
				int rt=LCA(x,y);
				if(ffa(x)!=rt) nt[x]=y;
				if(ffa(y)!=rt) nt[y]=x;

				shrink(x,rt);shrink(y,rt);
			}
			//增广
			else if(!match[y])
			{
				nt[y]=x;
				for(int j=y;j;)
				{
					int k=nt[j],z=match[k];
					match[j]=k;match[k]=j;
					j=z;
				}
				break;
			}
                        //之前匹配过
			else
			{
				nt[y]=x;
				q.push(match[y]);
				mark[match[y]]=1;
				mark[y]=2;
			}
		}
	}
}

int main()
{
	int m;
	scanf("%d%d",&n,&m);
	len=0;
	memset(first,0,sizeof(first));
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y);ins(y,x);
	}
	int ans=0;
	memset(match,0,sizeof(match));
	for(int i=1;i<=n;i++) if(!match[i]) augment(i);
	for(int i=1;i<=n;i++) if(match[i]) ans++;
	ans/=2;
	printf("%d\n",ans);
	for(int i=1;i<=n;i++) printf("%d ",match[i]);
	printf("\n");
	return 0;
}

  

?我认为所谓带花树的树,指匈牙利树,奇环缩点构成花?

2017-03-04 11:26:08

时间: 2024-10-11 05:04:17

【UOJ 79】 一般图最大匹配 (?带花树开花)的相关文章

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

zoj3316【一般图最大匹配 带花树开花】

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3726 算法见:http://fanhq666.blog.163.com/blog/static/8194342620120304463580/ 题意:棋盘上有n个点,现在两个人轮流在移除一个子,每次移除的子距离上次移除的子曼哈顿距离小于L.最后不能移除的人输. 分析:将距离小于L的点连边.如果一个连通块不是是完备匹配,先手一定可以让自己走到一个没有匹配的点上,然后后手就

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

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

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

UOJ #79 一般图最大匹配

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

一般图最大匹配带花树

参考博客: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)的 简述一下“带花树”算法吧: 它的核心思想还是找增广路.假设已经匹配好了一堆点,

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

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <string> using namespace std; const int MAXN = 250; int N; //点的个数,点的编号从1到N bool Graph[MAXN][MAXN]; int Match[MAXN]; bool InQueue[MAXN],I

kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数 König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选

URAL 1099. Work Scheduling 一般图匹配带花树

一般图匹配带花树模版题: 将奇环缩成圈(Blossom),然后找增广路..... 1099. Work Scheduling Time limit: 0.5 second Memory limit: 64 MB There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to sche