【学时·III】 二分图


■基本策略■

其实本质是图论中的网络流

二分图是两个由多个点组成的集合(上部和下部,且没有重叠),两个集合中的点不与该集合内其他的点连通,但和另一个集合内的点连通。我们称这两个集合为上部、下部,或X、Y部,比如:

  • 判定

我们可以通过染色的方法将一个普通的连通图转换为二分图(如果不是连通图,则说明该图存在多个二分图或不为二分图)。由于X部只与Y部相连,Y部也只与X部相连,我们可以把X、Y部染成不同的颜色。通过BFS(DFS也可以)从图里的一个点开始,假设它为X部,则与它相连的点为Y部,之后又为X部……直到访问到一个标记过的点,且该点的标记与将要作的标记不同,则不是二分图。将所有点标记完后还没有冲突,则是二分图。

  • 算法

与二分图相关的有匈牙利算法、König定理,分别处理增广路和最大匹配问题。

  • 最大匹配

二分图中若存在边集 E() 使得其中的边没有交点(共同的顶点),则称 E() 是该二分图的一个匹配。

特别的,若 E() 所含的顶点恰好是二分图中所有的顶点,则称 E() 为完全匹配。

最常考的是最大匹配,此时 E() 所包含的边的数量达到二分图中可能的最大数量。

  • 增广路径

边集 E() 为二分图已经匹配的边,路径P连接不同部的未匹配的点,若在P中匹配的边和未匹配的边交替出现,则称P为增广路径。可见P的边数一定是奇数,且因为起点和终点都未匹配,所以匹配边比未匹配边少1。

通过将增广路径反色——未匹配边换为匹配边,匹配边换为未匹配边,我们可以得到一个更好的匹配。当没有增广路径时,形成的匹配就是该二分图的最大匹配。

这种算法称为匈牙利算法。


■来一点版题■

◆没有技术含量◆ eXam

只要知道二分图的定义就可以了

这道题只需要判断给出的数据是否合法,且数据完美地分为X部(考试)、Y部(学生),因此就是一个标准的非连通图二分图判断。

考试与学生的关系可以看做连线,这样我们就得到了一个图,其实是多个图。可以通过遍历每一个没有标记的点来判别每一个连通图是否都是二分图,只要有一个不是,就判断"no"。这里作者用vector 的邻接表储存图,col[] 储存标记。

这里的方案其实就是X、Y部中的某一部。(⊙_⊙)

  • 源代码
/*Lucky_Glass*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int n_cla,n_stu,col[30005],error;
vector<int> vec[30005];
vector<int> ans;
void Solve(int u,int c)
{
col[u]=c;
if(c%2) ans.push_back(u);
for(int i=0;i<(int)vec[u].size();i++)
{
int v=vec[u][i];
if(col[v]){if((c+1)%2!=col[v]%2)error=true;continue;}
Solve(v,c+1);
if(error) return;
}
}
int main()
{
scanf("%d%d",&n_cla,&n_stu);
for(int i=1;i<=n_stu;i++)
{
int A,B;scanf("%d%d",&A,&B);
vec[B].push_back(A);vec[A].push_back(B);
}
for(int i=1;i<=n_cla;i++)
if(!col[i])
{
Solve(i,1);
if(error)
{
puts("no");
return 0;
}
}
printf("yes\n%d\n%d",ans.size(),ans[0]);
for(int i=1;i<(int)ans.size();i++)
printf(" %d",ans[i]);
return 0;
}

◆最大匹配◆ The Perfect Stall

把匈牙利算法的板套上去

  1. 图的建立

虽然二分图分为2个部(牛栏、奶牛),但实际上它还是一个图——所以必须将2个部的点放入同一个图中。这里可以通过将牛放入1~N的点,把牛栏放入N+1~N+M的点中。

2. 匈牙利算法的实现

寻找增广路径一般是采用DFS:

bool DFS(int u)
{
for(int i=0;i<(int)vec[u].size();i++) //枚举邻接点
{
int v=vec[u][i];
if(vis[v]) continue; //之前没有访问
vis[v]=true; //标记
if(mat[v]==0 || DFS(mat[v])) //如果该点没有匹配,或通过该点能向下找到一个未匹配点
{ //这就是一条增广路径
mat[u]=v;mat[v]=u; //反边
return true;
}
}
return false;
}

这道题比较基础,只要求找到最大匹配的数量,因此直接使用匈牙利算法,统计有多少组匹配就可以了。

  • 源代码
/*Lucky_Glass*/
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define MAXN 200
int n,m,mat[2*MAXN+5];
bool vis[2*MAXN+5];
vector<int> vec[2*MAXN+5];
bool DFS(int u)
{
for(int i=0;i<(int)vec[u].size();i++)
{
int v=vec[u][i];
if(vis[v]) continue;
vis[v]=true;
if(mat[v]==0 || DFS(mat[v]))
{
mat[u]=v;mat[v]=u;
return true;
}
}
return false;
}
int Solve()
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof vis);
if(mat[i]==0 && DFS(i))
ans++;
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
memset(mat,0,sizeof mat);
for(int i=1;i<=n;i++)
{
int n_;scanf("%d",&n_);
for(int j=0,x;j<n_;j++)
{
scanf("%d",&x);
vec[i].push_back(x+n);
vec[x+n].push_back(i);
}
}
printf("%d\n",Solve());
for(int i=1;i<=n;i++) vec[i].erase(vec[i].begin(),vec[i].end());
for(int i=1;i<=m;i++) vec[i+n].erase(vec[i+n].begin(),vec[i+n].end());
}
return 0;
}

◆最小覆盖◆ Machine Schedule

就像一道结论题,结论一发现,就没什么难点了

  1. König定理

最小覆盖点数=最大匹配数

下面是证明:





2. 所以这道题还是最大匹配~

  • 源代码
/*Lucky_Glass*/
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define MAXN 200
int n,m,mat[2*MAXN+5];
bool vis[2*MAXN+5];
vector<int> vec[2*MAXN+5];
bool DFS(int u)
{
for(int i=0;i<(int)vec[u].size();i++)
{
int v=vec[u][i];
if(vis[v]) continue;
vis[v]=true;
if(mat[v]==0 || DFS(mat[v]))
{
mat[u]=v;mat[v]=u;
return true;
}
}
return false;
}
int Solve()
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof vis);
if(mat[i]==0 && DFS(i))
ans++;
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
memset(mat,0,sizeof mat);
for(int i=1;i<=n;i++)
{
int n_;scanf("%d",&n_);
for(int j=0,x;j<n_;j++)
{
scanf("%d",&x);
vec[i].push_back(x+n);
vec[x+n].push_back(i);
}
}
printf("%d\n",Solve());
for(int i=1;i<=n;i++) vec[i].erase(vec[i].begin(),vec[i].end());
for(int i=1;i<=m;i++) vec[i+n].erase(vec[i+n].begin(),vec[i+n].end());
}
return 0;
}

The End

Thanks for reading!

- Lucky_Glass

【学时总结】 ◆学时·III◆ 二分图的更多相关文章

  1. springMVC文件上传与下载(六)

    1..文件上传 在springmvc.xml中配置文件上传解析器 <!-- 上传图片配置实现类,id必须为这个 --> <bean id="multipartResolve ...

  2. 如何使用和关闭onbeforeunload 默认的浏览器弹窗事件

    Onunload,onbeforeunload都是在刷新或关闭时调用,可以在<script>脚本中通过 window.onunload来指定或者在<body>里指定.区别在于o ...

  3. 教师表(TEACHER.DBF)

    20-27题使用的数据如表1和表2所示. 表1 教师表(TEACHER.DBF) 教师号 姓名 性别 籍贯 职称 年龄 工资/元 0001 王吉兵 男 江苏 讲师 27 2003.50 0002 张晓 ...

  4. 18级北航软件学院算法复习--Samshui

    A 比特手链 简单模拟 判断 贪心 叶姐要想哥赠送一串比特手链,这个手链由0和1组成.想哥买了手链B,无意间得知叶姐想要同样长度的手链A.想哥囊中羞涩,只能手工调整手链.他希望最少通过以下操作进行最少 ...

  5. 【学时总结】 ◆学时 · I◆ A*算法

    [学时·I]A*算法 ■基本策略■ --A*(A Star)无非就是BFS的升级,当BFS都超时的时候-- 同样以队列为基础结构,BFS使用FIFO队列(queue),而A*则使用优先队列(prior ...

  6. 【学时总结&模板时间】◆学时·10 & 模板·3◆ AC自动机

    ◇学时·10 & 模板·3◇ AC自动机 跟着高中上课……讲AC自动机的扩展运用.然而连KMP.trie字典树都不怎么会用的我一脸懵逼<(_ _)> 花一上午自学了一下AC自动机 ...

  7. 【学时总结】◆学时·IX◆ 整体二分

    ◆学时·IX◆ 整体二分 至于我怎么了解到这个算法的……只是因为发现一道题,明显的二分查找,但是时间会爆炸,被逼无奈搜题解……然后就发现了一些东西QwQ ◇ 算法概述 整体二分大概是把BFS与二分查找 ...

  8. 【学时总结】◆学时·VIII◆ 树形DP

    ◆学时·VIII◆ 树形DP DP像猴子一样爬上了树……QwQ ◇ 算法概述 基于树的模型,由于树上没有环,满足DP的无后效性,可以充分发挥其强大统计以及计算答案的能力. 一般来说树形DP的状态定义有 ...

  9. 【学时总结】◆学时·VII◆ 高维DP

    ◆学时·VII◆ 高维DP 自学之余,偶遇DP…… ◇ 算法概述 顾名思义——一种处理多方面状态的DP,这种DP特点是……每一维的大小都不算太大(不然用dp数组存储下来内存会炸),而且枚举时容易超时… ...

随机推荐

  1. CSS3 教程

    CSS3 教程 CSS 用于控制网页的样式和布局. CSS3 是最新的 CSS 标准. 本教程向您讲解 CSS3 中的新特性. 开始学习 CSS3!  更多:http://www.runoob.com ...

  2. 微服务&spring cloud架构系列汇总

    为了方便查找,把微服务&微服务架构之spring cloud架构系列文章按时间正序整理了一下,记录如下:   1. 微服务架构之spring cloud 介绍 2. 微服务架构之spring ...

  3. Android Editable

    在android的sdk中有讲,“This is the interface for text whose content and markup can be changed (as opposed ...

  4. MUI框架-13-使用百度地图 API(图文教程)

    MUI框架-13-使用百度地图 API(图文教程) 后面有实例,转载请注明出处 一.申请百度地图权限 1.打开 百度地图开放平台:http://lbsyun.baidu.com/apiconsole/ ...

  5. LoadRunner对移动互联网后端服务器压力测试

    一.LoadRunner简介 LoadRunner,是惠普公司研发的一款预测系统行为和性能的负载测试工具.通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner能够 ...

  6. MSSQL->serverlink[Oracle]

    需求描述:     SQL Server数据库连接Oracle数据库   条件准备:     SQL Server数据库,SQL Server 2008R2     Oracle数据库,Oracle ...

  7. MySQL案例05:CPU负载优化

    最近有套系统数据库周末总是告警,CPU使用率超过90%,开始由开发那边再跟进处理,我也就没参与,后来发现没进展就登录上去看了下,然后进行了部分优化,优化后效果还是比较明显的,具体优化过程本文会做详细的 ...

  8. python----------闭包 、装饰器

    闭包: 就是内层函数对外层函数(非全局变量的)非全局变量的引用 def func(): name = '老人家' def func1(): print(name)#局部变量对全局变量的引用 因为并没有 ...

  9. [翻译] HTKDragAndDropCollectionViewLayout

    HTKDragAndDropCollectionViewLayout Custom UICollectionViewLayout that works together with a custom U ...

  10. Linux(CentOS)网卡的基本设置

    临时设置 修改IP地址: ifconfig eth0 10.60.45.205 mask 255.255.255.0 修改网关地址 route add default gw 10.60.45.1 de ...