紫书:二分图匹配 最大流解决
网络流的一个经典应用是二分图匹配。
匹配是指:两两没有公共点的边集。
二分图是指:可以把结点集分成两部分X和Y,使得每条边恰好一个端点在XXX,另一个端点在YYY。换句话说,同色节点不相邻,进行二染色。
一般在画图的时候,把XXX结点和YYY结点画成左右两列。
可以证明一个图是二分图,当且仅当没有奇数圈。
当我们使用dinicdinicdinic跑二分图的时候,复杂度只有O(n12m)O(n^\frac{1}{2}m)O(n21m),但具体怎么求的之后介绍。
只需要知道复杂度非常优秀即可。
常见二分图匹配问题有两种:
最大基数匹配:包含最多匹配边数。
针对这样的问题,增加一个源点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;
}
紫书:二分图匹配 最大流解决相关推荐
- HDU 3081 Marriage Match II (并查集+二分+最大流 | 并查集+二分图匹配)
题意:n 个男生.n个女生玩游戏,每个女生都可以和她不讨厌的男生结婚,此外她的朋友如果也不讨厌这个男生,也可以和他结婚:对于女生,如果A和B是朋友,B和C是朋友,那么A和C也是朋友.每次游戏女生会找一 ...
- 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)...
题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...
- 洛谷P3386:网络流之二分图匹配,最大流算法
二分图:我的理解是,对图中的点集,可分为两个集合U和V,使得两个集合之间存在通路,且集合内部不存在通路.如上图. 匹配:两两不含公共端点的边集合M 最大匹配:边数最多的匹配 完美匹配:最大匹配的匹配数 ...
- 【网络流24题】搭配飞行员(最大流+二分图匹配)
传送门 搭配飞行员 题意:二分图匹配裸题,不多说 I think Dinic算法跑最大流解决||匈牙利算法 Code 代码一:Dinic #include<cstdio> #inc ...
- upc 6445: 棋盘V (网络流费用流解决匹配问题)
6445: 棋盘V 时间限制: 1 Sec 内存限制: 128 MB 提交: 325 解决: 31 [提交] [状态] [讨论版] [命题人:admin] 题目描述 有一块棋盘,棋盘的边长为100 ...
- [Cogs14] [网络流24题#1] 飞行员分配方案 [网络流,最大流,二分图匹配]
经典二分图匹配,可以用匈牙利算法,也可以用最大流 代码如下(Dinic): #include <iostream> #include <cstdio> #include < ...
- 网络流(二)最大流之二分图匹配
最大流之二分图匹配 二分图匹配模型匈牙利算法的复杂度为O(nm)O(nm)O(nm) 最大流(Dinic) 复杂度为O(mn)O(m\sqrt{n})O(mn). 二分图匹配问题见图方式较为固定,设 ...
- 匈牙利算法解决二分图匹配问题
匈牙利算法是由匈牙利数学家Edmonds于1965年提出.匈牙利算法是基于Hall定理中充分性证明的思想,它是二分图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的 ...
- 带权二分图匹配(最小费用最大流) 8.2牛客暑期多校训练营五 E
E.room | 时间限制:1 秒 | 内存限制:256M Nowcoder University has 4n students and n dormitories ( Four students ...
最新文章
- updatehf.vbs:自动打补丁
- lsof 查看进程打开那些文件 和 查看文件给那个进程使用
- <java并发编程实践>读书笔记二
- 知识图谱实体链接:一份“由浅入深”的综述
- 项目经理人必须要遵循的14个成功原则
- 关于python中excel写入案例
- 《MySQL—— 业务高峰期的性能问题的紧急处理的手段 》
- activemq发布订阅
- 蓝桥杯 BEGIN-4 入门训练 Fibonacci数列
- java无法加载主类_java运行显示“找不到或无法加载主类”!
- Bsie(鄙视IE)
- django1.10.3下admin后台管理老是显示object
- 玩转spring boot——结合jQuery和AngularJs
- google地图静态api使用助手(html源码)
- 炼成的:精妙SQL语句介绍
- 获取data-*属性值
- PotPlayer 和 VLC 播放器的书签
- C/C++程序员学习路线
- java 适配器_java里面的适配器是什么东西
- 计算机主板外频,笨鸟先飞 主板超频BIOS选项接触(图解)