学2分匹配 (模版)

转自 http://blog.csdn.net/q3498233/article/details/5786225

二分图:二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联的两个顶点恰好一个属于集合X,另一个属于集合Y。

二分图匹配:给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点(即2条匹配的边是没有公共顶点),则称M是一个匹配。
最大匹配:图中包含边数最多的匹配称为图的最大匹配。
完美匹配:如果所有点都在匹配边上,则称这个最大匹配是完美匹配。

二分图匹配基本概念:

未盖点
设VI是G的一个顶点,如果VI不与任意一条属于匹配M的边相关联,就称VI是一个未盖点。

交错轨

在匹配问题中,增广路径的表现形式是一条"交错路径",也就是说这条由图的边组成的路径, 它的第一条边是目前还没有参与匹配的,

第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配(并且始点和终点还没有被选择过,那就是增广路)。

可增广轨(增广路)
    两个端点都是未盖点的交错轨称为可增广轨。

可增广轨的性质:

1:P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
2:P经过取反操作可以得到一个更大的匹配M’。
3:M为G的最大匹配当且仅当不存在相对于M的增广路径。

二分图最大匹配匈牙利算法:

算法的思路是不停的找增广轨,并增加匹配的个数,增广轨顾名思义是指一条可以使匹配数变多的路径,在匹配问题中,增广轨的表现形式是一条"交错 轨",

也就是说这条由图的边组成的路径,它的第一条边是目前还没有参与匹配的,第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配,并且始点和 终点还没有被选择过.

这样交错进行,显然他有奇数条边.那么对于这样一条路径,我们可以将第一条边改为已匹配,第二条边改为未匹配...以此类推.也就是 将所有的边进行"取反",容易发现这样修改以后,

匹配仍然是合法的,但是匹配数增加了一对.另外,单独的一条连接两个未匹配点的边显然也是交错轨.可以证 明,当不能再找到增广轨时,就得到了一个最大匹配.

这也就是匈牙利算法的思路。

月老的难题

时间限制:1000 ms  |  内存限制:65535 KB

难度:4

描述

月老准备给n个女孩与n个男孩牵红线,成就一对对美好的姻缘。

现在,由于一些原因,部分男孩与女孩可能结成幸福的一家,部分可能不会结成幸福的家庭。

现在已知哪些男孩与哪些女孩如果结婚的话,可以结成幸福的家庭,月老准备促成尽可能多的幸福家庭,请你帮他找出最多可能促成的幸福家庭数量吧。

假设男孩们分别编号为1~n,女孩们也分别编号为1~n。

输入
第一行是一个整数T,表示测试数据的组数(1<=T<=400)
每组测试数据的第一行有两个整数n,K,其中男孩的人数与女孩的人数都是n。(n<=500,K<=10 000)
随后的K行,每行有两个整数i,j表示第i个男孩与第j个女孩有可能结成幸福的家庭。(1<=i,j<=n)
输出
对每组测试数据,输出最多可能促成的幸福家庭数量
样例输入
1
3 4
1 1
1 3
2 2
3 2
样例输出
2
 1 #include<stdio.h>
 2 #include<string.h>
 3 int vis[10000],match[10000],head[10000];//match[]记录匹配点
 4 struct node
 5 {
 6     int v;
 7     int next;
 8 }edge[10030];
 9 int n,m,inddex;
10 void add(int x,int y)
11 {
12     edge[inddex].v=y;
13     edge[inddex].next=head[x];
14     head[x]=inddex++;
15 }
16 int dfs(int u)
17 {
18     int i,j;
19     for(i=head[u];i!=-1;i=edge[i].next)
20     {
21         int tt=edge[i].v;
22         if(!vis[tt])
23         {
24             vis[tt]=1;
25             if(match[tt]==-1||dfs(match[tt]))//如果tt未在前一个匹配M中,或者tt在匹配M中,但是从与tt相邻的节点出发可以有增广路径
26             {
27                 match[tt]=u;//记录查找成功记录,更新匹配M(即“取反”) 
28                 return 1;
29             }
30         }
31     }
32     return 0;
33 }
34 int main()
35 {
36     int i,j,t;
37     scanf("%d",&t);
38     while(t--)
39     {
40         memset(match,-1,sizeof(match));
41         memset(head,-1,sizeof(head));
42         scanf("%d%d",&n,&m);
43         inddex=1;
44         for(i=0;i<m;i++)
45         {
46             int x,y;
47             scanf("%d%d",&x,&y);
48             add(x,y);
49         }
50         int ans=0;
51         for(i=1;i<=n;i++)
52         {
53             memset(vis,0,sizeof(vis));
54             if(dfs(i))
55                 ans++;
56         }
57         printf("%d\n",ans);
58     }
59 }

时间: 2024-10-11 14:08:17

学2分匹配 (模版)的相关文章

HDU 1281 棋盘游戏 (2分匹配)

 棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2649    Accepted Submission(s): 1546 Problem Description 小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的"车",并且使得他们不能互相攻击,这当然很简单,但是Gardo

&lt;图论算法之2分匹配&gt; hdu 1281(棋盘游戏)

题意: 给一个n*m的棋盘,在上面放上车,放的车之间不能相互攻击(在同一行或者同一列就能相互攻击),并且只有某些点能放车. 问最多能放多少车,其中有多少个格子必须放才能放最多的车. 这是一道很好的理解匈牙利算法的题目.  首先我们求最多放多少车,这是一个行列匹配问题.假设我们用n个左边的点代表行 ,m个右边的点放在右边,如果一个格子(x,y)能放车,那么将左边的x和右边的y连接一起建一条边.这个一个很经典的模型,就不必多少了.用匈牙利算法求一次最大匹配. 后面这一问很好.首先我说说最暴力的方法.

POJ 1486 (2分匹配 必须变判断)

建图很好想到,主要是后面判断这条匹配边是不是必须变. 只需要吧当前这个匹配拆开,并且在图中吧这条边去掉.对对于左边的点去找增光路,如果不能找到,说明就是匹配必须边. #include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<queue> #include<stack> #include<string> #include&

快学Scala-09--模式匹配

1.匹配字符串 A => 1  B => 2  C => 3 //传统方法 def getNum(msg:String):Int={ if(msg=="A") 1 else if (msg=="B") 2 else if (msg=="C") 3 else 4 } //模式匹配方法 def getNum(msg:String):Int={ msg match{ case "A" => 1 case &q

二分匹配模版

http://blog.csdn.net/asmcos/article/details/46676101 http://blog.csdn.net/asmcos/article/details/46676087 http://blog.csdn.net/asmcos/article/details/46676073 http://blog.csdn.net/asmcos/article/details/46676053 http://blog.csdn.net/asmcos/article/de

小白学react之网页获取微信用户信息

通过上一篇<小白学react之EJS模版实战>我们学习了如何通过EJS模版生成我们高定制化的index.html文件. 本篇我们将会继续延续我们的alt-tutorial项目的实战计划,去获取微信扫码用户的信息,并将头像显示在我们页面的右上角上. 最终实战效果将如下所示. 首先根据我们的网站url生成二维码,比如我们可以通过浏览器的FeHelper来生成: 然后用户通过微信扫码: 最后用户确定授权后获取到用户的基本信息,并将头像显示在右上角: 1. 内网穿透准备 我们获取微信用户信息的过程中,

【转】科大校长给数学系学弟学妹的忠告&amp;本科数学参考书

1.老老实实把课本上的题目做完.其实说科大的课本难,我以为这话不完整.科大的教材,就数学系而言还是讲得挺清楚的,难的是后面的习题.事实上做1道难题的收获是做10道简单题所不能比的. 2.每门数学必修课至少要看一本参考书,尽量做一本习题集. 3.数学分析别做吉米,除非你太无聊,推荐北大方企勤的习题集.此外注意一下有套波兰的数学分析习题集,是不是搞得到中文或英文版. 4.线性代数推荐普罗斯库列科夫的<<线性代数习题集>>和法捷耶夫的<<高等代数习题集>>.莫斯科

2015黑龙江省赛记

            应该说从高中毕业后就很少写过文章了,其实这篇文章本来是学校要求写成比赛总结,想了想发篇博文得了.接下来我要讲述这段下学期的传奇经历,出现的人名字母代替.全文就围绕省赛来说吧,整个大一历程,暑假后描述.           因为是山东的上学期基本疯狂玩耍,期末照样年级12,但是实际编程水平真的是谈不上,但始终种着一颗开始编程的种子,结果这学期让他萌发了!从这学期才开始正式刷oj题目.夜也熬过,课该逃的能逃的 基本都没落下!经历了校赛被虐,之后全身心投入省赛选拔.好了故事就此

xdoj

1000.a+b. #include<bits/stdc++.h> using namespace std; int a,b; int main() { ios::sync_with_stdio(false); while(cin >> a >> b) cout << a+b << endl; return 0; } 1001.直接开数组回爆内存,于是自己开个一维数组存放元素,大小需要自己斟酌.(或者动态数组) 直接处理对应位置,根据最后对应的位