二分图G(E,V)将点集合V分成两个部分L,R,使得,图G中所有属于E的边相关联的两个点分别在L和R中。
二分图的一个匹配,即是图G中的边集合,其中,任意两条边都不共用一个顶点,或者说,每个顶点都之多只有一条边和它相关联。
二分图中的最大匹配M,就是求边数最大的边集合。
求二分图匹配有很多算法,这里介绍两种,效率都是O(EV)。
一、将最大匹配问题规约为最大流问题。
构造一个s源点,构造s到左边顶点集合中,每一个顶点的边。构造一个t汇点,构造右边顶点集合中,每一个顶点到t的边。把图中所有的边容量设为1,那么求原图的最大匹配即是求流网络的最大流。具体参考算法导论
二、匈牙利算法
具体参考:http://imlazy.ycool.com/post.1603708.html
代码模板
最大匹配的应用: 1.二分匹配的直接模拟 2.图的最小点覆盖数 = 图的最大匹配数; zoj_1516
zoj_1525 zoj_2223 #include<iostream>
#include<cstdio>
#include<string.h>
#include<map>
using namespace std;
int const MAXI=51;
bool useif[MAXI];
int links[MAXI];
bool array[MAXI][MAXI];
int left_num,right_num;
bool can(int t)
{
for(int i=0;i<right_num;i++)
{
if(!useif[i]&&array[t][i])
{
useif[i]=true;
if((links[i]==-1)||can(links[i]))
{
links[i]=t;
return true;
}
}
}
return false;
}
3.图的最大点独立集 = 图顶点数 - 图的最大匹配数;
4.图的最小路径覆盖数 = 原图的顶点数 - 原图拆点后形成的二分图的最大匹配数;#include<iostream>
#include<cstdio>
#include<string.h>
#include<map>
using namespace std;
int const MAXI=51;
bool useif[MAXI];
int links[MAXI];
bool array[MAXI][MAXI];
int left_num,right_num;
bool can(int t)
{
for(int i=0;i<right_num;i++)
{
if(!useif[i]&&array[t][i])
{
useif[i]=true;
if((links[i]==-1)||can(links[i]))
{
links[i]=t;
return true;
}
}
}
return false;
}
int row,col,pond;
bool grid[101][101];
int main()
{
freopen("e:\\zoj\\zoj_1516.txt","r",stdin);
while(scanf("%d %d",&row,&col)!=EOF&&row&&col)
{
map<int,int>lp;
lp.clear();
map<int,int>rp;
rp.clear();
scanf("%d",&pond);
int r,c;
memset(grid,false,sizeof(grid));
memset(array,false,sizeof(array));
for(int i=0;i<pond;++i)
{
scanf("%d %d",&r,&c);
grid[r-1][c-1]=true;
}
int lindex=0;
int rindex=0;
left_num=right_num=0;
for(int i=0;i<row;++i)
{
for(int j=0;j<col;++j)
{
if(!grid[i][j])
{
if((i+j)%2==0)
{
left_num++;
lp[col*i+j]=lindex;
lindex++;
}
else
{
right_num++;
rp[col*i+j]=rindex;
rindex++;
}
}
}
}
for(int i=0;i<row;++i)
{
for(int j=0;j<col;++j)
{
if(!grid[i][j])
{
if(i+1<row&&!grid[i+1][j])
{
if((i+j)%2==0)
array[lp[col*i+j]][rp[col*(i+1)+j]]=true;
else
array[lp[col*(i+1)+j]][rp[col*i+j]]=true;
}
if(j+1<col&&!grid[i][j+1])
{
if((i+j)%2==0)
array[lp[col*i+j]][rp[col*i+j+1]]=true;
else
array[lp[col*i+j+1]][rp[col*i+j]]=true;
}
}
}
}
for(int i=0;i<MAXI;i++)
links[i]=-1;
int res=0;
for(int i=0;i<left_num;++i)
{
memset(useif,0,sizeof(useif));
if(can(i))
++res;
}
printf("%d\n",res);
}
}
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const int MAXI=125;
bool useif[MAXI];
int links[MAXI];
bool array[MAXI][MAXI];
int left_num,right_num;
bool can(int t)
{
for(int i=0;i<right_num;i++)
{
if(!useif[i]&&array[t][i])
{
useif[i]=true;
if((links[i]==-1)||can(links[i]))
{
links[i]=t;
return true;
}
}
}
return false;
}
int cases;
int e,v,from,to;
int main()
{
freopen("e:\\zoj\\zoj_1525.txt","r",stdin);
scanf("%d",&cases);
while(cases--)
{
memset(array,false,sizeof(array));
for(int i=0;i<MAXI;i++)
links[i]=-1;
scanf("%d",&v);
scanf("%d",&e);
left_num=right_num=v;
while(e--)
{
scanf("%d %d",&from,&to);
array[from-1][to-1]=true;
}
int res=0;
for(int i=0;i<left_num;i++)
{
memset(useif,false,sizeof(useif));
if(can(i))
++res;
}
printf("%d\n",v-res);
}
}
#include<iostream>
#include<cstdio>
#include<string.h>
#include<map>
using namespace std;
int cases;
bool useif[30];
int links[30];
int left_num,right_num;
bool array[30][30];
int lcards[30];
int rcards[30];
map<char,int>mv;
map<char,int>ms;
bool can(int t)
{
for(int i=0;i<right_num;i++)
{
if(!useif[i]&&array[t][i])
{
useif[i]=true;
if((links[i]==-1)||can(links[i]))
{
links[i]=t;
return true;
}
}
}
return false;
}
int main()
{
freopen("e:\\zoj\\zoj_2223.txt","r",stdin);
ms['C']=0;
ms['D']=1;
ms['S']=2;
ms['H']=3;
mv['2']=2;
mv['3']=3;
mv['4']=4;
mv['5']=5;
mv['6']=6;
mv['7']=7;
mv['8']=8;
mv['9']=9;
mv['T']=10;
mv['J']=11;
mv['Q']=12;
mv['K']=13;
mv['A']=14;
scanf("%d",&cases);
while(cases--)
{
char value,suit;
int k;
scanf("%d",&k);
left_num=right_num=k;
for(int i=0;i<k;i++)
{
getchar();
scanf("%c%c",&value,&suit);
lcards[i]=mv[value]*4+ms[suit];
}
for(int i=0;i<k;i++)
{
getchar();
scanf("%c%c",&value,&suit);
rcards[i]=mv[value]*4+ms[suit];
}
memset(array,false,sizeof(array));
for(int i=0;i<30;i++)
links[i]=-1;
for(int i=0;i<k;i++)
{
for(int j=0;j<k;j++)
{
if(lcards[i]<rcards[j])
{
array[i][j]=true;
}
}
}
int res=0;
for(int i=0;i<left_num;i++)
{
memset(useif,0,sizeof(useif));
if(can(i))
++res;
}
printf("%d\n",res);
}
return 0;
}
发表评论
-
图的割点tarjan---zoj_1119
2011-10-24 23:00 1232http://acm.zju.edu.cn/on ... -
BFS与双向BFS---zoj_1505
2011-10-09 17:14 1642http://acm.zju.edu.c ... -
静态treap+线段树---zoj_2112
2011-09-29 23:06 1708http://acm.zju.edu ... -
NIM博弈游戏,SG函数---zoj_3084,zoj_2083
2011-09-23 23:00 1316Nim游戏是两个人进行的游戏有如下规则: ... -
多重背包--zoj_2156
2011-09-14 11:10 864首先介绍经典的三种背包问题,0-1背包,完全 ... -
模式串匹配---KMP
2011-08-31 20:49 1277朴素的的模式串匹配算法通常要在向前移动文本指针 ... -
八数码问题(A*&&双向BFS)---zoj_1217
2011-08-30 22:13 1665题目地址:http://acm.zju.edu.cn/onli ... -
ac自动机以及它上面的DFA
2011-08-08 23:04 2479AC自动机(Aho-Corasick)主要用 ... -
网络最大流(EK)---zoj_1734
2011-07-19 16:34 2130网络最大流是图论中的一个典型问题,为了精确的定 ... -
trie和前缀检查---zoj_2876
2011-07-13 23:03 866trie树是一种多叉树,广泛用于字典检索。如 ... -
位图bitmap
2011-07-13 21:08 914bitmap是一种广泛使用的数据结构,主要用在 ... -
LAC和RMQ的转化---zoj_3195
2011-07-12 22:35 1072我擦。。纠结了好久啊,从SF到TLE,先总结2 ... -
LAC的tarjan(离线)算法---zoj_1141
2011-07-08 17:52 1658LCA就不解释了,这里主要再次复习一下LC ... -
笛卡尔树以及treap---zoj_2243
2011-07-07 15:52 2839zoj_2243笛卡 ... -
线段染色,矩形切割,离散化---zoj_2301,zoj_1128
2011-06-24 22:32 1364染色问题:在一维坐标轴上(最右端为M),有N ... -
线段树---zoj_1610
2011-06-22 21:06 744线段树是一种二叉树的拓展,在线段树每个节点中 ... -
快速排序(qsort)
2011-06-16 17:03 776快速排序是一种高效的非稳定排序,它的基本思路 ... -
斐波那契散列
2011-06-16 16:38 3073斐波那契散列法其实是一种特殊的乘法散列,先来看乘法 ... -
强连通分支(scc)---tarjan
2011-06-15 16:17 1283本文大量 ... -
单源最短路径SPFA---zoj3146
2011-06-09 15:25 940针对Bellman-Ford算法效率比较低 ...
相关推荐
ZOJ解题报告ZOJ解题报告ZOJ解题报告ZOJ解题报告
ZOJ题解集合-截至2835。共1244个文件,C/C++,有重复
zoj网站中多个练习的c++解答,文件名即为题目序号。经本人测试可以使用,主要为动态规划方面的问题,希望给初学者提供帮助。
zoj题目简单归类zoj题目简单归类zoj题目简单归类
acm中zoj1002的可运行C++程序
包含了zoj700多道题目的源代码,在做题时可以参考
zoj 1140-zju 2433 简单题的部分答案 都是可以正确通过的,简洁易懂
Problem Arrangement zoj 3777
ZOJ题目答案源码
学习ACM程序设计的朋友一定要看,这是训练必备的POJ ZOJ题目分类及解题思路
一个非常非常非常非常实用的zoj结题代码
zoj 1003 c语言的,要写这么多描述吗。。
ZOJ1805代码
本代码是zoj上AC的1951的代码,把双重循环简化为O(n),不过素数判断的改进还不够
ZOJ完全解题报告,喜欢ACM的同学,欢迎下载
浙大ZOJ题目分类,可以让你更方便快速锁定那你想要联系的题目,是自己快速提高·
zoj1027解题指南和代码,还不错,是学校培训给的。
zoj 题库 详细解答 解题代码 acm
zoj4041正确题解源代码,以及运行程序
acm 模板 算法 浙大 zoj zju acm初学者必备 代码