图的最大匹配问题: poj_1469
2016-03-10 21:05
211 查看
#include <iostream>
//二分图的最大匹配问题,POJ149
//匈牙利算法
/*最大流算法的核心问题就是找增广路径(augment path)。匈牙利算法也不例外,它的基本模式就是:
初始时最大匹配为空
while 找得到增广路径
do 把增广路径加入到最大匹配中去
最小点覆盖数: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。
可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖=最小路径覆盖=|N|-最大匹配数
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。
把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',
如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
*/
using namespace std;
bool g[110][310];//邻接矩阵,100门课程,300个学生。
bool flag,visited[310];//记录某个学生是否被访问过
int match[310];//记录与学生匹配的课程号
int p,n;//课程数和学生人数
int link[110];
bool dfs(int u){
for(int i =1;i<=n;i++){
if(g[u][i]&&!visited[i]){//如果节点i与节点u可以相连并且未被访问过
visited[i] = true;//标记其被查过
if(match[i]==-1 || dfs(match[i])) //如果i未在之前的匹配中,或者i在
//之前的匹配m中,但是从与i相邻的节点出发可以由增广路径
{
match[i] = u;//记录查找成功的记录,更新匹配
return true;
}
}
}
return false;
}
int main()
{
int i,j,k,t,v,ans;
cin>>t;
while(t--){
cin>>p>>n;
for(i=1;i<=p;i++){
for(j=1;j<=n;j++)
g[i][j] = false;
}
for(i=1;i<=n;i++)
match[i] = -1;
flag =true;
for(i=1;i<=p;i++){
cin>>k;
if(k==0)
flag =false;
while(k--){
cin>>v;
g[i][v] = true;
}
}
if(flag){
ans =0;
for(i=1;i<=p;i++){
for(j=1;j<=300;j++)
visited[j] = false;
if(dfs(i))
ans++;
}
if(ans==p){
cout<<"YES!"<<endl;
cout<<"最大匹配是:";
for(i=1;i<=300;i++){
if(match[i] !=-1){
link[match[i]] = i;
}
}
for(j =1;j<=p;j++){
cout<<j<<"->"<<link[j]<<endl;
}
}
else
cout<<"NO"<<endl;
}
else
cout<<"NO"<<endl;
}
//cout << "Hello world!" << endl;
return 0;
}
//二分图的最大匹配问题,POJ149
//匈牙利算法
/*最大流算法的核心问题就是找增广路径(augment path)。匈牙利算法也不例外,它的基本模式就是:
初始时最大匹配为空
while 找得到增广路径
do 把增广路径加入到最大匹配中去
最小点覆盖数: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。
可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖=最小路径覆盖=|N|-最大匹配数
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。
把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',
如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
*/
using namespace std;
bool g[110][310];//邻接矩阵,100门课程,300个学生。
bool flag,visited[310];//记录某个学生是否被访问过
int match[310];//记录与学生匹配的课程号
int p,n;//课程数和学生人数
int link[110];
bool dfs(int u){
for(int i =1;i<=n;i++){
if(g[u][i]&&!visited[i]){//如果节点i与节点u可以相连并且未被访问过
visited[i] = true;//标记其被查过
if(match[i]==-1 || dfs(match[i])) //如果i未在之前的匹配中,或者i在
//之前的匹配m中,但是从与i相邻的节点出发可以由增广路径
{
match[i] = u;//记录查找成功的记录,更新匹配
return true;
}
}
}
return false;
}
int main()
{
int i,j,k,t,v,ans;
cin>>t;
while(t--){
cin>>p>>n;
for(i=1;i<=p;i++){
for(j=1;j<=n;j++)
g[i][j] = false;
}
for(i=1;i<=n;i++)
match[i] = -1;
flag =true;
for(i=1;i<=p;i++){
cin>>k;
if(k==0)
flag =false;
while(k--){
cin>>v;
g[i][v] = true;
}
}
if(flag){
ans =0;
for(i=1;i<=p;i++){
for(j=1;j<=300;j++)
visited[j] = false;
if(dfs(i))
ans++;
}
if(ans==p){
cout<<"YES!"<<endl;
cout<<"最大匹配是:";
for(i=1;i<=300;i++){
if(match[i] !=-1){
link[match[i]] = i;
}
}
for(j =1;j<=p;j++){
cout<<j<<"->"<<link[j]<<endl;
}
}
else
cout<<"NO"<<endl;
}
else
cout<<"NO"<<endl;
}
//cout << "Hello world!" << endl;
return 0;
}
相关文章推荐
- Problem B: 复制字符串
- 【SSH网上商城】对依赖注入的理解
- 虚拟机安装
- 【Struts2进阶】Struts2深度解析ModelDriven原理
- PHP开发典型模块
- Linux命令总结
- 自定义一个SharedPreferences工具类
- 第二周项目二就拿胖子说事
- LeetCode:String to Integer (atoi)
- 项目2-就拿胖子说事
- 【android】ListView 的 transcriptMode 选项
- NYOJ 贪心 喷水装置二
- [置顶] 利用python进行折线图,直方图和饼图的绘制
- 矩阵十大经典题目
- hdu 2089 不要62
- PHP从入门到精通 读书笔记
- android-利用broadcast双程序相互监控保证目标程序运行
- 图论 最小生成树 和最短路
- OpenCV与CUDA混合编程
- 201603102057_《Javascript之观察者模式(模块间通讯)》