最小割:
对于一个网络流图,把整张图分割成两个部分,一部分包含源点,一部分包含汇点的分割方式叫做割。
割的容量即切割边时所切去边的容量之和,其中使割的容量最小的割叫做最小割
求法:
一张网络流图的最小割等于它的最大流,至于怎么证明可以看一下这篇博客这里本人太菜就不证明了。
既然知道了它们相等,那么就可以跑最大流的模板来找最小割了
常见模型:
小M的作物
上面有一道题,里面就用到了一个最小割的模型,即二选一模型。
这种模型大概就是,有一些点集可以被分到连个集合中,分到A花费为XXX,分到B花费为XXX。
费用流:
费用流就是对于每条边,经过流量时是需要收费的,收费的数目和流量成正比,通常题目给的都是每条边通过每单位流量需要花费多少。
最小费用最大流,MCMF算法:
最小费用最大流就是要求在流量最大时,尽可能的减少花费。
通常的做法就是用spfa代替bfs,然后求最大流,这就是MCMF算法。
为啥要这么做呢?
每条边的费用可以看做边的权重,从s流向t就可以看做找一条边权和最小的增广路。于是就可以用spfa代替bfs然后跑出来的就是最小费用最大流。
至于为什么这样正确,其实很明显,因为每次spfa跑出来的就是当前费用最低的增广路,所以把这些加起来就是一定是最小费用。
模板:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
int h[maxn],n,m,s,t,cnt = 2;
int pre[maxn],incf[maxn],dis[maxn];//pre用于记录路径,incf记录流,dis记录费用
ll maxFlow,maxCost;
bool vis[maxn];
struct node{
int cost,e,nex,flow;
}e[maxn * 2];
void add(int a,int b,int f,int cost){
e[cnt].e = b;
e[cnt].nex = h[a];
e[cnt].cost = cost;
e[cnt].flow = f;
h[a] = cnt++;
}
bool spfa(){
//spfa
for(int i = 1; i <= n; i++)vis[i] = 0,dis[i] = INF;
vis[s] = 1,dis[s] = 0,incf[s] = INF;
queue<int> qu;
qu.push(s);
while(!qu.empty()){
int tmp = qu.front();
vis[tmp] = 0;
qu.pop();
for(int i = h[tmp]; i ; i = e[i].nex){
int endd = e[i].e;
if(!e[i].flow)continue;//如果没残余流量了就不走
if(dis[endd] > dis[tmp] + e[i].cost){
pre[endd] = i;
dis[endd] = dis[tmp] + e[i].cost;
incf[endd] = min(incf[tmp],e[i].flow);
if(!vis[endd])qu.push(endd),vis[endd] = 1;
}
}
}
if(dis[t] == INF)return 0;
else return 1;
}
void MCMF(){
//MCMF本体
while(spfa()){
int x = t;
maxCost += (ll)dis[t] * incf[t];//最小费
maxFlow += incf[t];//最大流
while(x != s){
//更新所有路径的流的状况
e[pre[x]].flow -= incf[t];
e[pre[x] ^ 1].flow += incf[t];
x = e[pre[x] ^ 1].e;
}
}
}
/*
4 5 1 4
3 1 3
3 1 2
2 3 2
3 4 3
4 2 1
*/
题目:
最近写到的一道多校题目:这里
一道很不错的最小费用最大流的变形