二分图模板总结 nyoj 239 月老的难题 && poj 1468 COURSES
2014-05-05 11:20
260 查看
二分图最大匹配 匈牙利算法 模板题
时间限制: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)
输出
对每组测试数据,输出最多可能促成的幸福家庭数量
样例输入
样例输出
这里用邻接表存储,还可以用邻接矩阵,hash等
这几位大神写的更详细些,可以再参考参考:二分图的最大匹配
匈牙利算法求二分图的最大匹配
匈牙利算法模板
模板中核心部分都一样,我用的int 型map和vis数组(vector中用link)进行标记(0或1),其实也可以用bool 型,这样更能节省空间
若用邻接矩阵存,超时,不过这种方法可以做
poj1469 COURSES 这题
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;
#define MAXN 550
int map[MAXN][MAXN];
int vis[MAXN];
int link[MAXN];
int n,m;
bool find(int x)
{
for(int i = 1; i <= m;i++)
{
if(vis[i]==0&&map[x][i])
{
vis[i]=1;
if(link[i]==0 || find(link[i]))
{
link[i]=x;
return true;
}
}
}
return false ;
}
int MaxMatch()
{
memset(link,0,sizeof(link));
int count = 0 ;
for(int i = 1; i <= n ; i++)
{
memset(vis,0,sizeof(vis));
if(find(i))
count ++;
}
return count ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(map,0,sizeof(map));
for(int i = 1 ; i <= n ; i++)
{
int t;
scanf("%d",&t);
for(int j = 1 ; j <= t ; j++){
int k ;
scanf("%d",&k);
map[i][k]=1;
}
}
if(MaxMatch()== n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
变1 :
在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是“二分图的最小顶点覆盖”:
二分图的最小顶点覆盖数 = 二分图的最大匹配数
例题:hdu 1150 Machine Schedule
变2:DAG图(无回路有向图)的最小路径覆盖
用尽量少的不相交简单路径覆盖有向无环图(DAG)的所有顶点,这就是DAG图的最小路径覆盖问题。
DAG图的最小路径覆盖数 = 节点数(n)- 最大匹配数(m)
例题:hdu 1151 Air Raid
这题直接套前面的模板就行,把输入格式改改,最后用n - MaxMatch()得到答案
变3: [b]二分图的最大独立集
二分图的最大独立集数 = 节点数(n)- 最大匹配数(m)
关键:求二分图的最大匹配数
例题:hdu 1068 Girls and Boys
此题相当于有向图,最大匹配/2
月老的难题
时间限制: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
这里用邻接表存储,还可以用邻接矩阵,hash等
这几位大神写的更详细些,可以再参考参考:二分图的最大匹配
匈牙利算法求二分图的最大匹配
匈牙利算法模板
模板中核心部分都一样,我用的int 型map和vis数组(vector中用link)进行标记(0或1),其实也可以用bool 型,这样更能节省空间
#include<algorithm> #include<cstring> #include<stdio.h> #include<vector> using namespace std; #define MAXN 550 vector<int> v[MAXN]; /*用STL中的vector建立邻接表实现匈牙利算法 效率比较高*/ int vis[MAXN]; //记录v[x]中结点是否访问过 int link[MAXN]; int n,m; bool find(int x) { for(int j= 0 ; j < v[x].size(); j++) { if(vis[v[x][j]]==0)//如果节点i与j相连并且未被查找过 { vis[v[x][j]]=1; //标记i为已查找过 if(link[v[x][j]]==0||find(link[v[x][j]])) { //如果j是起始节点或者与j相连的结点出发有增广路径 link[v[x][j]]=x; return true; } } } return false; } int MaxMatch() { memset(link,0,sizeof(link)); int count = 0 ; for(int i = 1; i <= n ; i++) { memset(vis,0,sizeof(vis)); if(find(i)) count ++; } return count; } int main() { int N,star,to; scanf("%d",&N); while(N--) { memset(v,0,sizeof(v)); scanf("%d%d",&n,&m); for(int i = 0 ; i < m ; i++) { scanf("%d%d",&star,&to); v[star].push_back(to); } printf("%d\n",MaxMatch()); } return 0; }
若用邻接矩阵存,超时,不过这种方法可以做
poj1469 COURSES 这题
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;
#define MAXN 550
int map[MAXN][MAXN];
int vis[MAXN];
int link[MAXN];
int n,m;
bool find(int x)
{
for(int i = 1; i <= m;i++)
{
if(vis[i]==0&&map[x][i])
{
vis[i]=1;
if(link[i]==0 || find(link[i]))
{
link[i]=x;
return true;
}
}
}
return false ;
}
int MaxMatch()
{
memset(link,0,sizeof(link));
int count = 0 ;
for(int i = 1; i <= n ; i++)
{
memset(vis,0,sizeof(vis));
if(find(i))
count ++;
}
return count ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(map,0,sizeof(map));
for(int i = 1 ; i <= n ; i++)
{
int t;
scanf("%d",&t);
for(int j = 1 ; j <= t ; j++){
int k ;
scanf("%d",&k);
map[i][k]=1;
}
}
if(MaxMatch()== n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
变1 :
在二分图中求最少的点,让每条边都至少和其中的一个点关联,这就是“二分图的最小顶点覆盖”:
二分图的最小顶点覆盖数 = 二分图的最大匹配数
例题:hdu 1150 Machine Schedule
#include<algorithm> #include<cstring> #include<stdio.h> #include<vector> using namespace std; #define MAXN 550 int map[MAXN][MAXN]; int vis[MAXN]; int link[MAXN]; int n,m; bool find(int x) { for(int i = 1; i <= n; i++) { if(vis[i]==0&&map[x][i]==1 ) { vis[i]=1; if(link[i]==0 || find(link[i])) { link[i]=x; return true; } } } return false ; } int MaxMatch() { memset(link,0,sizeof(link)); int count = 0 ; for(int i = 1; i <= m ; i++)//这里的m和find函数里的n可以互换 {//原因是都是在二分图的一个集合中遍历另一个集合的最优匹配 memset(vis,0,sizeof(vis));//所以两个集合谁遍历谁都一样 if(find(i)) count ++; } return count ; } int main() { while(scanf("%d",&n),n) { int k; scanf("%d%d",&m,&k); memset(map,0,sizeof(map)); for(int i = 1 ; i <= k ; i++) { int a,b,c; scanf("%d%d%d",&c,&a,&b); map[a]=1; } printf("%d\n",MaxMatch()); } return 0; }
变2:DAG图(无回路有向图)的最小路径覆盖
用尽量少的不相交简单路径覆盖有向无环图(DAG)的所有顶点,这就是DAG图的最小路径覆盖问题。
DAG图的最小路径覆盖数 = 节点数(n)- 最大匹配数(m)
例题:hdu 1151 Air Raid
这题直接套前面的模板就行,把输入格式改改,最后用n - MaxMatch()得到答案
变3: [b]二分图的最大独立集
二分图的最大独立集数 = 节点数(n)- 最大匹配数(m)
关键:求二分图的最大匹配数
例题:hdu 1068 Girls and Boys
此题相当于有向图,最大匹配/2
#include<algorithm> #include<cstring> #include<stdio.h> #include<vector> using namespace std; #define MAXN 550 int map[MAXN][MAXN]; int vis[MAXN]; int link[MAXN]; int n,m; bool find(int x) { for(int i = 0; i < n; i++) { if(vis[i]==0&&map[x][i]==1 ) { vis[i]=1; if(link[i]==0 || find(link[i])) { link[i]=x; return true; } } } return false ; } int MaxMatch() { memset(link,0,sizeof(link)); int count = 0 ; for(int i = 0; i < n ; i++) { memset(vis,0,sizeof(vis)); if(find(i)) count ++; } return count ; } int main() {//注意每一题的取值范围,此题为0--n-1 while(scanf("%d",&n)!=EOF) { memset(map,0,sizeof(map)); for(int i = 0 ; i < n ; i++) { int a,b,c; scanf("%d: (%d)",&a,&b); for(int j = 0 ; j < b ; j++) { scanf("%d",&c); map[a][c]=1; } } printf("%d\n",(n-MaxMatch()/2));//这题相当于有向图,循环两遍因此除以2 } return 0; }
相关文章推荐
- NYOJ239 月老的难题 【二分图最大匹配·匈牙利】
- NYOJ 237 NYOJ 239 二分图 最大匹配模板题 游戏高手的烦恼 月老的难题 两个题一样
- NYOJ 题目239 月老的难题 (二分图最大匹配-匈牙利算法模板)
- NYOJ 题目239月老的难题(二分图最大匹配,邻接表)
- nyoj239 月老的难题 二分图 匈牙利算法
- NYOJ 239 月老的难题(二分图最大匹配)
- NYOJ - 239 - 月老的难题 ( 二分图最大匹配 匈牙利算法 )
- nyoj-239 月老的难题 (二分图匹配—匈牙利算法 && 网络流—Dinic算法)
- NYOJ239 月老的难题 二分图最大匹配(前向星)
- NYOJ239 月老的难题 【二分图最大匹配·匈牙利】
- nyoj 239 月老的难题 二分图最大匹配(匈牙利算法)
- NYoj 239 :月老的难题(二分图最大匹配,匈牙利算法)
- nyoj 239 月老的难题 【二分图&&最大匹配&&匈牙利算法】
- NYOJ——239月老的难题(二分图最大匹配)
- nyoj 239 月老的难题<二分图匹配>
- NYOJ239月老的难题(二分图的最大匹配模版)
- NYOJ 239 月老的难题
- 二分图匹配算法之匈牙利算法模板 hdoj1083 nyoj月老的难题
- nyoj 239 月老的难题 【二分匹配之匈牙利】
- nyoj239月老的难题