Problem Description

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

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

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

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

Input

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

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

Output

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

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

Examples

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

思路:

题目本质是给出 n 个点 m 条边的无向图,要求一个最大匹配并输出任意一种方案

对于一般图的匹配,使用带花树算法即可,本题是一个带花树裸题

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
const int MOD = 1073741824;
const int N = 3000+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;struct Edge {int to,next;
} edge[N*N*2];
int head[N],tot;
int n;//n个点
int father[N],pre[N];//father记录一个点属于哪个一个点为根的花
int Q[N*N*2],first,tail;//bfs队列
int match[N];//匹配
bool odd[N],vis[N];//odd记录一个点为奇点/偶点,1为奇,0为偶
int timeBlock;//LCA时间戳
int top[N],rinedge[N];void addEdge(int x,int y) {//添边edge[tot].to=y;edge[tot].next=head[x];head[x]=tot++;
}
int Find(int x){//并查集寻找根节点if(father[x]!=x)return father[x]=Find(father[x]);return x;
}
int lca(int x, int y){//求解最近公共祖先timeBlock++;while(x){rinedge[x]=timeBlock;x=Find(top[x]);}x=y;while(rinedge[x]!=timeBlock)x=Find(top[x]);return x;
}
void blossom(int x, int y, int k) {//将奇环缩成一个点并将原来是奇点的点变为偶点并加入队列while(Find(x)!=Find(k)){pre[x]=y;y=match[x];odd[y]=false;Q[tail++]=y;father[Find(x)]=k;father[Find(y)]=k;x=pre[y];}
}
bool bfs(int s) {memset(top,0,sizeof(top));memset(pre,0,sizeof(pre));memset(odd,false,sizeof(odd));memset(vis,false,sizeof(vis));for(int i=1;i<=n;i++)father[i]=i;vis[s]=true;first=tail=0;Q[tail++]=s;while(first!=tail){int now=Q[first++];for(int i=head[now];i!=-1;i=edge[i].next){int to=edge[i].to;if(!vis[to]){top[to]=now;pre[to]=now;odd[to]=true;vis[to]=true;if(!match[to]){int j=to;while(j){int x=pre[j];int y=match[x];match[j]=x;match[x]=j;j=y;}return true;}vis[match[to]]=true;top[match[to]]=to;Q[tail++]=match[to];}else if(Find(now)!=Find(to) && odd[to]==false) {int k=lca(now,to);blossom(now,to,k);blossom(to,now,k);}}}return false;
}int main() {memset(head,-1,sizeof(head));memset(match,0,sizeof(match));tot=0;int m;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);addEdge(x,y);addEdge(y,x);}int res=0;for(int i=1;i<=n;i++)if(!match[i])res+=bfs(i);printf("%d\n",res);for(int i=1;i<=n;i++)printf("%d ",match[i]);printf("\n");return 0;
}

一般图最大匹配(UOJ-79)相关推荐

  1. 【学习小记】一般图最大匹配——带花树算法

    Text 一般图的最大匹配仍然是基于寻找增广路的 增广路的定义是这样的一条路径,它不经过重复的点,并且路径两端均没有匹配,且整条路径是非匹配边-匹配边-非匹配边这样交错的. 类比二分图最大匹配的增广路 ...

  2. [转]带花树,Edmonds's matching algorithm,一般图最大匹配

    看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树--其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...

  3. URAL - 1099 Work Scheduling(一般图最大匹配-带花树模板)

    题目链接:点击查看 题目大意:给出n个警卫,接下来给出数个关系,表示两个警卫可以互相配合,现在规定只有可以互相配合的警卫才能留下来继续工作,问最多能有多少个警卫留下来工作,输出匹配方案 题目分析:一般 ...

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

    所谓花,就是如下图所示的一个奇环: 本文中粗边代表现在的匹配边,细边代表该点的前驱(后文会讲解前驱是什么,现在只需要知道每个点和它的前驱在原图中一定是有边的). 如图所示,一朵包含\(2k+1\)个点 ...

  5. 模板 - 一般图最大匹配(带花树)

    整理的算法模板合集: ACM模板 目录 题目描述 给出一张 n 个点 m 条边的无向图,求该图的最大匹配. 总结一下带花树算法的流程 1.每次找一个未匹配的点出来增广 2.在增广过程中,如果相邻点是白 ...

  6. HDU - 3551 Hard Problem(一般图最大匹配)

    题目链接:点击查看 题目大意:给出一张无向图,问能否删除任意数量的边,使得每个点的度数都达到指定的数值 题目分析:参考博客:https://www.cnblogs.com/xiongtao/p/111 ...

  7. HDU - 4687 Boke and Tsukkomi(一般图最大匹配-带花图)

    题目链接:点击查看 题目大意:给出n个人和m对匹配,现在问有多少组匹配是不必要的,按照升序输出答案 题目分析:因为题目给的N比较小,所以一开始我的想法是先计算出最大匹配,而后枚举每一条边被删除,然后计 ...

  8. 2020牛客多校第1场I-1 or 2一般图最大匹配带花树

    链接:https://ac.nowcoder.com/acm/contest/5666/I Bobo has a graph with n vertices and m edges where the ...

  9. uoj79 一般图最大匹配 带花树学习(被虐

    辣鸡蒟蒻原来的blog: http://www.elijahqi.win/2018/01/28/uoj79/ 学习资料其一:http://www.csie.ntnu.edu.tw/~u91029/Ma ...

最新文章

  1. [UIImage imageNamed:@]使用误区
  2. Linux--线程编程
  3. 【Python】list 之 extend 和 append 的区别
  4. 2016-12-31:最后一天:回顾
  5. const 一级指针的启示
  6. 开源 免费 java CMS - FreeCMS-信息页静态化参数 .
  7. 如何在Linux中符号链接文件? [关闭]
  8. shop++源码反编译----随笔
  9. 摩尔庄园同一服务器怎么显示好友,摩尔庄园手游怎么搜索别人搜索好友步骤详解...
  10. MDM主数据清洗和编码集成说明
  11. IDEA安装插件及安装失败的处理方法
  12. 虚幻行为树EQS(环境查询)
  13. CTF密码学总结(一)
  14. CDMA sid, nid, bid 含义解释
  15. scrapy抓取淘宝女郎 1
  16. C#初学日记21.11.25
  17. 谷贱伤农,薪贱伤码农!
  18. linux里用dnf安装软件,Linux 软件包管理器 DNF 的使用方法
  19. c语言:关于vs2012使用easyX的loadimage()加载资源图片
  20. PHP上传视频超出大小,你指定要上传的文件或文件大小超过限制解决方法

热门文章

  1. 数据库函数..........
  2. Java笔记(四)各类容器,set,map,队列实现
  3. 2022数据库排行榜新鲜出炉!MySQL大势已去,PostgreSQL即将崛起!
  4. 程序员到底会不会修电脑?
  5. 再有人问你什么是ThreadLocal,就把这篇文章甩给他!
  6. DevOps是微服务的秘方
  7. Essentials of Deep Learning: Visualizing Convolutional Neural Networks in Python
  8. [].slice.call
  9. atcoder 2643 切比雪夫最小生成树
  10. 【Android】ListView ViewHolder ArrayIndexOutOfBoundsException: length=2; index=2