热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Dinic算法实现二分图匹配

在学习匈牙利算法的时候便知道网络流可以以更小的时间复杂度解决同样的问题近期学了网络流,刚好可以再来玩儿玩儿二分图其实Dinic算法在解决二分图匹配的时候和普通的网络流题目并没有太大区别,主

在学习匈牙利算法的时候便知道网络流可以以更小的时间复杂度解决同样的问题
近期学了网络流,刚好可以再来玩儿玩儿二分图

其实Dinic算法在解决二分图匹配的时候和普通的网络流题目并没有太大区别,主要就是建图
此时,你肯定想打我,因为网络流大部分都是考建图(逃
具体说一下对于二分图这种特殊的图应该怎么建图(捂脸

给一张二分图,一个集合X中含有n个元素,另一个集合Y中含有m个元素

首先,把二分图中互相连接的点连接起来,设权值为1。恩,这一步可以看做翻译题目;
然后,找到一个超级源点和一个超级汇点。通常前者找0,后者找n+m+1;
最后,将X中的元素都与超级源点连起来,Y中的元素都和超级汇点连起来。这些边的权值都为1;

建图完成,搞定收工(雾

从超级源点到超级汇点跑一波Dinic,最大匹配就素最大流啦!
至于证明,显然可得嘛!(划掉)网上草鸡多证明的,自己百度啦~
毕竟,我不在意那些细节所以我不会。不服你打我啊~~

来一道很简单的题目,先说匈牙利算法是可以AC滴~~~

【rqnoj140】寻找代表元


题目描述
温中一共有n个社团,分别用1到n编号。
温中一共有m个人,分别用1到m编号。每个人可以参加一个或多个社团,也可以不参加任何社团。
每个社团都需要选一个代表。我们希望更多的人能够成为代表。


输入格式
第一行输入两个数n和m。以下n行每行若干个数,这些数都是不超过m的正整数。其中第i行的数表示社团i的全部成员。每行用一个0结束。


输出格式
输出最多的能够成为代表的人数。


数据范围
n,m<=200


样例输入
4 4
1 2 0
1 2 0
1 2 0
1 2 3 4 0


样例输出
3

唔,裸题不想解释太多了。给你个眼神自己做!

#include
#include
#include
#include
#define INF 1e8
using namespace std;
const int maxn=1005;
struct Edge{int from,to,cap,flow;};
int n,m,s,t,k,x;
vectoredges;
vector<int>G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void AddEdge(int from,int to,int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
k=edges.size();
G[from].push_back(k-2);
G[to].push_back(k-1);
}
bool BFS(){
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
d[s]=0;
vis[s]=true;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=0;i Edge& e=edges[G[x][i]];
if(!vis[e.to] && e.cap>e.flow){
vis[e.to]=true;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a){
if(x==t || a==0) return a;
int flow=0,f;
for(int &i=cur[x];i Edge& e=edges[G[x][i]];
if(d[x]+1==d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int MaxFlow(int s,int t){
int flow=0;
while(BFS()){
memset(cur,0,sizeof(cur));
flow+=DFS(s,INF);
}
return flow;
}
int main(){
scanf("%d%d",&n,&m);
s=0,t=n+m+1;
for(int i=1;i<=n;i++){
scanf("%d",&x);
while(x!=0){AddEdge(i,x+n,1);scanf("%d",&x);}
}
for(int i=1;i<=n;i++)
AddEdge(s,i,1);
for(int i=1;i<=m;i++)
AddEdge(i+n,t,1);
printf("%d\n",MaxFlow(s,t));
return 0;
}

PS:二分图匹配的题都可以用这种方法去操一下。
毕竟匈牙利能做的Dinic也能,Dinic能做的匈牙利不一定能。

————
菜鸡我发现当年写错了个地方qwq


推荐阅读
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
author-avatar
Echocc07
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有