网络流的一个经典应用是二分图匹配
匹配是指:两两没有公共点的边集。
二分图是指:可以把结点集分成两部分X和Y,使得每条边恰好一个端点在XXX,另一个端点在YYY。换句话说,同色节点不相邻,进行二染色
一般在画图的时候,把XXX结点和YYY结点画成左右两列。
可以证明一个图是二分图,当且仅当没有奇数圈
当我们使用dinicdinicdinic跑二分图的时候,复杂度只有O(n12m)O(n^\frac{1}{2}m)O(n21​m),但具体怎么求的之后介绍。
只需要知道复杂度非常优秀即可。
常见二分图匹配问题有两种:


最大基数匹配:包含最多匹配边数
针对这样的问题,增加一个源点sss,一个汇点ttt,从sss到XXX各连接一个容量为1的弧,同理,ttt和YYY也连接。对于每条边直接相连,也是容量为1,跑一遍最大流即是最大匹配
前面容量为1限制了XXX和YYY各自只能匹配一次。其实中间的容量是无所谓的,因为已经实现了对唯一匹配的限制。
求出最大流之后,原图中所有流量为1的弧(起点终点在不同边)即是最佳匹配。


针对带权图,需要求出边权最大的匹配
与此同时,有两种情况,要求这个匹配本身是完美匹配(每个点都被匹配到)。或者不要求。
如果要求的话,把权值赋为相反值,求最小费用最大流即可,加上判断源点和汇点的所有弧是否流量都为1,如果不是,说明不能满足完美匹配。
对于第二种情况,我们只需要每次增广按1增加,同时记录答案取最优即可。
因为是这样的,我们求解的时候可能费用最大的出现在流量较小的时候,但是最小费用最大流是直接计算到最大流。处理的方式很简单,求出最小改进量,如果大于1,令它等于1即可。


引入一道例题:Uva1349
题目要求找若干个有向圈,每个点恰好属于一个圈,要求权值和尽可能小。
对于一个圈,每个点都有唯一的前驱和后驱,对于每条边必定对应某个点的前驱和某个点的后驱。
我们定义每条边就是从前驱指向后驱,每个点拆分成两个点前驱和后驱
最后实现前驱和后驱唯一匹配即可(同时需要完美匹配),不能够自己匹配自己。(实际上给出的边点不一样必然是不会出现自己匹配自己的。)
代码如下:最小费用最大流求解二分图最小权完美匹配问题

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;#define ll long long
#define eps 1e-6
#define inf 0x3f3f3f3f
const int maxn=2500;struct Edge{int from,to;ll cap,flow,cost;
};struct MCMF{int n,tmp,s,t;vector<Edge>edges;vector<int>G[maxn];int inq[maxn];ll d[maxn];//spfaint p[maxn];//上一条弧便于回溯ll a[maxn];//最小改进量void init(int n,int s,int t){this->n=n,this->s=s,this->t=t;edges.clear();for(int i=1;i<=n;i++)G[i].clear();}void AddEdge(int from,int to,ll cap,ll cost){edges.push_back((Edge){from,to,cap,0,cost});edges.push_back((Edge){to,from,0,0,-cost});tmp=edges.size();G[from].push_back(tmp-2);G[to].push_back(tmp-1);}bool spfa(int s,int t,ll& flow,ll& cost){for(int i=0;i<=n;i++)d[i]=inf;memset(inq,0,sizeof(inq));d[s]=0,inq[s]=1,p[s]=0,a[s]=inf;queue<int>Q;Q.push(s);while(!Q.empty()){int u=Q.front();Q.pop();inq[u]=0;for(int i=0;i<G[u].size();i++){Edge& e=edges[G[u][i]];if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){d[e.to]=d[u]+e.cost;//松弛p[e.to]=G[u][i];//记录上一条弧a[e.to]=min(a[u],e.cap-e.flow);//最小可改进量if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;}//入队}}}if(d[t]==inf)return false;//说明不连通了。flow+=a[t];//如果固定流量的话,可以在flow+a>=k的时候只增广到k,然后终止程序cost+=d[t]*a[t];int u=t;while(u!=s){edges[p[u]].flow+=a[t];edges[p[u]^1].flow-=a[t];u=edges[p[u]].from;}return true;}ll Mincost(){//绝对不能有负权圈,否则连续最短路的数学证明失效ll flow=0,cost=0;while(spfa(s,t,flow,cost));bool ok=true;for(int i=0;i<G[n-1].size();i++){Edge& e=edges[G[n-1][i]];if(e.flow<1)ok=false;}for(int i=0;i<G[n].size();i++){Edge& e=edges[G[n][i]^1];if(e.flow<1)ok=false;}if(ok)cout<<cost<<endl;else puts("N");return flow;}
}mf;int main(){int n,m;while(~scanf("%d",&n)&&n){mf.init(2*n+2,2*n+1,2*n+2);FOR(i,1,n){mf.AddEdge(2*n+1,i,1,0);mf.AddEdge(n+i,2*n+2,1,0);}FOR(i,1,n){int j;while(scanf("%d",&j)&&j){ll c;scanf("%lld",&c);mf.AddEdge(i,n+j,1,c);}}mf.Mincost();}return 0;
}

紫书:二分图匹配 最大流解决相关推荐

  1. HDU 3081 Marriage Match II (并查集+二分+最大流 | 并查集+二分图匹配)

    题意:n 个男生.n个女生玩游戏,每个女生都可以和她不讨厌的男生结婚,此外她的朋友如果也不讨厌这个男生,也可以和他结婚:对于女生,如果A和B是朋友,B和C是朋友,那么A和C也是朋友.每次游戏女生会找一 ...

  2. 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)...

    题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...

  3. 洛谷P3386:网络流之二分图匹配,最大流算法

    二分图:我的理解是,对图中的点集,可分为两个集合U和V,使得两个集合之间存在通路,且集合内部不存在通路.如上图. 匹配:两两不含公共端点的边集合M 最大匹配:边数最多的匹配 完美匹配:最大匹配的匹配数 ...

  4. 【网络流24题】搭配飞行员(最大流+二分图匹配)

    传送门 搭配飞行员     题意:二分图匹配裸题,不多说 I think Dinic算法跑最大流解决||匈牙利算法 Code 代码一:Dinic #include<cstdio> #inc ...

  5. upc 6445: 棋盘V (网络流费用流解决匹配问题)

    6445: 棋盘V 时间限制: 1 Sec  内存限制: 128 MB 提交: 325  解决: 31 [提交] [状态] [讨论版] [命题人:admin] 题目描述 有一块棋盘,棋盘的边长为100 ...

  6. [Cogs14] [网络流24题#1] 飞行员分配方案 [网络流,最大流,二分图匹配]

    经典二分图匹配,可以用匈牙利算法,也可以用最大流 代码如下(Dinic): #include <iostream> #include <cstdio> #include < ...

  7. 网络流(二)最大流之二分图匹配

    最大流之二分图匹配 二分图匹配模型匈牙利算法的复杂度为O(nm)O(nm)O(nm) 最大流(Dinic) 复杂度为O(mn)O(m\sqrt{n})O(mn​). 二分图匹配问题见图方式较为固定,设 ...

  8. 匈牙利算法解决二分图匹配问题

    匈牙利算法是由匈牙利数学家Edmonds于1965年提出.匈牙利算法是基于Hall定理中充分性证明的思想,它是二分图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的 ...

  9. 带权二分图匹配(最小费用最大流) 8.2牛客暑期多校训练营五 E

    E.room | 时间限制:1 秒 | 内存限制:256M Nowcoder University has 4n students and n dormitories ( Four students ...

最新文章

  1. updatehf.vbs:自动打补丁
  2. lsof 查看进程打开那些文件 和 查看文件给那个进程使用
  3. <java并发编程实践>读书笔记二
  4. 知识图谱实体链接:一份“由浅入深”的综述
  5. 项目经理人必须要遵循的14个成功原则
  6. 关于python中excel写入案例
  7. 《MySQL—— 业务高峰期的性能问题的紧急处理的手段 》
  8. activemq发布订阅
  9. 蓝桥杯 BEGIN-4 入门训练 Fibonacci数列
  10. java无法加载主类_java运行显示“找不到或无法加载主类”!
  11. Bsie(鄙视IE)
  12. django1.10.3下admin后台管理老是显示object
  13. 玩转spring boot——结合jQuery和AngularJs
  14. google地图静态api使用助手(html源码)
  15. 炼成的:精妙SQL语句介绍
  16. 获取data-*属性值
  17. PotPlayer 和 VLC 播放器的书签
  18. C/C++程序员学习路线
  19. java 适配器_java里面的适配器是什么东西
  20. 计算机主板外频,笨鸟先飞 主板超频BIOS选项接触(图解)

热门文章

  1. 使用nvm下载node和npm
  2. C++知识点总结及习题
  3. 风控ML[11] | 3种连续变量分箱方法的代码分享
  4. oracle解除被锁定的表的状态
  5. 如何在bilibili中查找弹幕发送者
  6. php将文章生成word,用php生成word模板
  7. 毕设论文怎么调格式(字体字号要求 章节自动编号 图表按照章节自动编号)
  8. cpu被锁频解除方法_CPU如何去锁频 CPU去锁频的方法
  9. 通过poi-tl实现报告的循环导出
  10. DataStage作业开发步骤