最小费用最大流模板
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入输出格式
输入格式:
第一行包含四个正整数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
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=5000,M<=50000
样例说明:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; #define INF 9764648 struct bian{ int to; int vol; int cost; int nex; }a[100009]; queue<int>q; int head[5009],pre[5009],path[5009],dis[5009]; int flag[5001]; int n,m,s,t,cnt=1,minn,minf[5009]; int flow=0,mincost=0; int u,v,f,w; void into() { for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&u,&v,&f,&w); a[++cnt].to=v; a[cnt].vol=f; a[cnt].cost=w; a[cnt].nex=head[u]; head[u]=cnt; a[++cnt].to=u; a[cnt].vol=0; a[cnt].cost=-w; a[cnt].nex=head[v]; head[v]=cnt; } } bool spfa( ) { memset(pre,-1,sizeof(pre)); memset(dis,127,sizeof(dis)); memset(flag,0,sizeof(f)); while(!q.empty()) q.pop(); q.push(s); dis[s]=0; pre[s]=0; flag[s]=1; minf[s]=INF; int tot=0;minn=INF; while( ! q.empty() ) { int u=q.front(); flag[u]=0; q.pop(); for(int e=head[u] ; e ; e=a[e].nex ) { int v=a[e].to; if(a[e].vol>0&&dis[u]+a[e].cost<dis[v]) { pre[v]=u; dis[v]=dis[u]+a[e].cost; path[v]=e; minf[v]=min(minf[u],a[e].vol); if(!flag[v]) flag[v]=1,q.push(v); 判断加在里边 } } } if(dis[t]>=INF) return false; return true; } void minflow() { while(spfa()) { int f=minf[t]; flow+=f; mincost+=f*dis[t]; int k=t; while(k!=s) { a[path[k]].vol-=f; a[path[k]^1].vol +=f; k=pre[k]; } } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); into(); minflow(); cout<<flow<<' '<<mincost; return 0; }
如图,最优方案如下:
第一条流为4-->3,流量为20,费用为3*20=60。
第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。
第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。
故最大流量为50,在此状况下最小费用为60+60+160=280。
故输出50 280。
出错较多,
*链表从2开始存比较适合(便于找对边,不会丢数据)
*广搜可能重复找到一个点不能以是否入队判断