洛谷-P3381 【模板】最小费用最大流(最小费用路算法)
2018-01-09 11:23
405 查看
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。输入格式:
第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出格式:
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。输入样例#1:
4 5 4 3 4 2 30 2 4 3 20 3 2 3 20 1 2 1 30 9 1 3 40 5
输出样例#1:
50 280
思路
题意很简单,就是求最小费用流,主要说一下算法。最小费用路算法的思想是:先找最小费用路,在该路径上面增流,增加到最大流。
利用邻接表建立双向边,正向边的花费为
cost,反向边的花费为
-cost.
在找最小费用路的时候,从源点出发,沿着可行 (E[i].cap>E[i].flow)广度搜索每个邻接点, 如果当前的边可以继续松弛,那么就更新,就是
SPFA算法,并且记录一下前驱。
当找到最小费用路以后,那么就从汇点向源点找一条,最小的可增流量,沿着增广路正向增流,反向减流,最后花费的费用为:
min
4000
cost=dis[V]∗d
累加这个过程求出来的就是最小费用,最大流就是每次累加的可增流量
代码
#include <cstdio> #include <cstring> #include <cctype> #include <stdlib.h> #include <string> #include <map> #include <iostream> #include <stack> #include <cmath> #include <queue> #include <vector> #include <algorithm> using namespace std; typedef long long ll; #define inf 1000000 #define mem(a,b) memset(a,b,sizeof(a)) const int N=5000+20; const int M=50000+20; int top;//当前边下标 int dis ,pre ;//源点到点i的最小距离,pre[i]记录前驱 bool vis ;//标记数组 int maxflow; int first ;//存储头结点 struct Edge { int v,next; int cap,flow,cost; } E[M*2]; void init() { mem(first,-1); top=0; maxflow=0; } void add_edge(int u,int v,int c,int cost) { E[top].v=v; E[top].cap=c; E[top].flow=0; E[top].cost=cost; E[top].next=first[u]; first[u]=top++; } void add(int u,int v,int c,int cost) { add_edge(u,v,c,cost); add_edge(v,u,0,-cost); } bool spfa(int s,int t,int n) { int i,u,v; queue<int>q; mem(vis,false); mem(pre,-1); for(int i=1; i<=n; i++) dis[i]=inf; vis[s]=true; dis[s]=0; q.push(s); while(!q.empty()) { u=q.front(); q.pop(); vis[u]=false; for(int i=first[u]; i!=-1; i=E[i].next) { v=E[i].v; if(E[i].cap>E[i].flow&&dis[v]>dis[u]+E[i].cost) { dis[v]=dis[u]+E[i].cost; pre[v]=i; if(!vis[v]) { q.push(v); vis[v]=true; } } } } if(dis[t]==inf) return false; return true; } int MCMF(int s,int t,int n)//minCostMaxFlow { int d; int i,mincost=0;//maxflow当前最大流量,mincost当前最小费用 while(spfa(s,t,n))//表示找到了从s到t的最小费用路 { d=inf; for(int i=pre[t]; i!=-1; i=pre[E[i^1].v]) //遍历反向边 d=min(d,E[i].cap-E[i].flow); maxflow+=d;//更新最大流 for(int i=pre[t]; i!=-1; i=pre[E[i^1].v]) //增广路上正向边流量+d,反向边流量-d { E[i].flow+=d; E[i^1].flow-=d; } mincost+=dis[t]*d;//dis[t]为该路径上单位流量费用之和 } return mincost; } int main() { int n,m,st,ed; int u,v,w,c; scanf("%d%d%d%d",&n,&m,&st,&ed); init(); for(int i=1; i<=m; i++) { scanf("%d%d%d%d",&u,&v,&w,&c); add(u,v,w,c); } int mincost=MCMF(st,ed,n); printf("%d %d\n",maxflow,mincost); return 0; }
相关文章推荐
- 网络流相关算法总结,最大流EK算法,SAP算法,最小费用最大流,最小费用路算法,最大流最小割定理
- 【模板】最小费用最大流(增广路)(模板题:洛谷P3381)
- 洛谷 最小费用最大流 模板 P3381
- 最小费用最大流;最小费用路算法;
- 最小费用路算法模板
- 洛谷P3381 【模板】最小费用最大流(dijstra费用流)
- 洛谷 P3381 【模板】最小费用最大流
- 最小费用最大流模板
- 最小费用最大流模板 poj 2135
- 【模板】匈牙利算法 二分图匹配 (模版题:洛谷P3386)
- 洛谷3805:【模板】manacher算法——题解
- [洛谷3366]【模板】最小生成树
- 洛谷——P3366 【模板】最小生成树
- 最小费用最大流模板
- 求解最小生成树的算法 kruskal算法(附模板)
- P3381 【模板】最小费用最大流
- 1834: [ZJOI2010]network 网络扩容 (最小费用最大流模板)
- 模板_krustra最小生成树算法
- [洛谷3381]【模板】最小费用最大流
- 洛谷 P3366 【模板】最小生成树