费用流
在求网络的最大流的同时加上一个条件:每条边的流过流的单位费用,由此得出费用流的问题
【其实费用流就可以算是最大流和最短路最长路的综合】
费用流问题分为两类:
最小费用最大流(最大流+最短路)
最大费用最大流(最大流+最长路)
最小费用最大流
为什么说最小费用最大流就是最大流+最短路呢,
可以这样想:
有一条流量为f的增广路,对于其中的每一条边都有一个单位费用cost[i],每条边的流量都是f,求出这一条增广路上所有边的单位费用之和Cost,那么这一条增广路的花费就是Cost*f
操作方法:
- 先用最短路算法寻找出一条单位费用之和最小的路
- 记录这条路上的最小容量,更新这条路上的所有边
- 重复上述操作,知道没有增广路
代码实现:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int len_edge
const int len_node
struct Edge{
int to,weight,cost
}edge[len_edge];
int head[len_node],nxt[len_edge],cnt;
int num_node,num_edge,s,t;
struct Dis{
int id,dis;
Dis(int order,int d){
id=order;
dis=d;
}
bool operator < (const Dis &a) const {
return dis>a.dis;
}
};
void init(){
memset(head,-1,sizeof(head));
memset(nxt,-1,sizeof(nxt));
cnt=-1;
}
void addEdge(int u,int v,int w,int c){
edge[++cnt].to=v;
edge[cnt].weight=w;
edge[cnt].cost=c;
nxt[cnt]=head[u];
head[u]=cnt;
edge[++cnt].to=u;
edge[cnt].weight=0;
edge[cnt].cost=-c;
nxt[cnt]=head[v];
head[v]=cnt;
}
int dis[len_node],inq[len_node],x,y;
int prePoint[len_node],preEdge[len_node];
Dis point;
bool SPFA(){ //因为有负权边(-c) 所以不能使用dijkstra算法
memset(dis,inf,sizeof(dis));
memset(inq,0,sizeof(inq));
memset(prePoint,-1,sizeof(prePoint));
priority_queue<Dis>node;
node.push( Dis(s,0) );
dis[s]=0;
inq[s]=1;
while(!node.empty()){
point=node.front();
node.pop();
x=point.id;
inq[x]=0;
for(int i=head[x];i!=-1;i=nxt[i]){
y=edge[i].to;
if(edge[i].weight){
if(dis[y]>dis[x]+edge[i].cost){
dis[y]=dis[x]+edge[i].cost;
prePoint[y]=x;
preEdge[y]=i;
if(!inq[y]){
node.push( Dis(y,dis[y]) );
inq[y]=1;
}
}
}
}
}
return dis[t]!=inf;
}
int mincost(){
int id,flow,cost=0,maxflow=0;
while(SPFA()){
x=t;
flow=inf;
while(prePoint[x]!=-1){ //求这一条增广路的流
id=preEdge[x];
flow=min(flow,edge[id].weight);
x=prePoint[x];
}
x=t;
while(prePoint[x]!=-1){ //更新增广路上的容量
id=preEdge[x];
edge[id].weight-=flow;
edge[id^1].weight+=flow;
}
cost+=flow*dis[t];
//maxflow+=flow; 如果需要求出最大流的话
}
return cost;
}
int main(){
//按照题目的逻辑写就可以了
}