1. 程式人生 > >洛谷P3381 【模板】最小費用最大流(dijstra費用流)

洛谷P3381 【模板】最小費用最大流(dijstra費用流)

就是 tro fin https copy priority 而不是 ++ printf

題目描述

如題,給出一個網絡圖,以及其源點和匯點,每條邊已知其最大流量和單位流量費用,求出其網絡最大流和在最大流情況下的最小費用。

輸入輸出格式

輸入格式:

第一行包含四個正整數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

(BYX:最後兩個點改成了1200ms)

數據規模:

對於30%的數據:N<=10,M<=10

對於70%的數據:N<=1000,M<=1000

對於100%的數據:N<=5000,M<=50000

樣例說明:

技術分享圖片

如圖,最優方案如下:

第一條流為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。

dijstra費用流真的不是一般的快

直接吊打SPFA

有一篇寫的不錯的博客

http://www.yhzq-blog.cc/%E6%9C%80%E5%B0%8F%E8%B4%B9%E7%94%A8%E6%9C%80%E5%A4%A7%E6%B5%81%E7%AE%97%E6%B3%95%E6%80%BB%E7%BB%93/

另外就是最後一句話為什麽是*h,而不是*dis

我個人的理解,因為在求最短路的時候有h的存在,所以這裏的dis已經不是實際上的dis,而h才是實際上的dis

// luogu-judger-enable-o2
#include<cstdio>
#include
<cstring> #include<queue> #define Pair pair<int,int> #define fi first #define se second #define AddEdge(x,y,f,z) add_edge(x,y,f,z);add_edge(y,x,0,-z); #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++) char buf[1<<20],*p1=buf,*p2=buf; using namespace std; const int MAXN=1e6+1,INF=1e8+10; inline int read() { char c=getchar();int x=0,f=1; while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } int N,M,S,T; struct node { int u,v,f,w,nxt; }edge[MAXN]; int head[MAXN],num=2; inline void add_edge(int x,int y,int f,int z) { edge[num].u=x; edge[num].v=y; edge[num].f=f; edge[num].w=z; edge[num].nxt=head[x]; head[x]=num++; } int h[MAXN],dis[MAXN],PrePoint[MAXN],PreEdge[MAXN]; Pair Dij() { int ansflow=0,anscost=0; while(1) { priority_queue<Pair>q; memset(dis,0xf,sizeof(dis)); dis[S]=0; q.push(make_pair(0,S)); while(q.size()!=0) { Pair p=q.top();q.pop(); if(-p.fi!=dis[p.se]) continue; if(p.se==T) break; for(int i=head[p.se];i!=-1;i=edge[i].nxt) { int nowcost=edge[i].w+h[p.se]-h[edge[i].v]; if(edge[i].f>0&&dis[edge[i].v]>dis[p.se]+nowcost) { dis[edge[i].v]=dis[p.se]+nowcost; q.push(make_pair(-dis[edge[i].v],edge[i].v)); PrePoint[edge[i].v]=p.se; PreEdge[edge[i].v]=i; } } } if(dis[T]>INF) break; for(int i=0;i<=N;i++) h[i]+=dis[i]; int nowflow=INF; for(int now=T;now!=S;now=PrePoint[now]) nowflow=min(nowflow,edge[PreEdge[now]].f); for(int now=T;now!=S;now=PrePoint[now]) edge[PreEdge[now]].f-=nowflow, edge[PreEdge[now]^1].f+=nowflow; ansflow+=nowflow; anscost+=nowflow*h[T]; } return make_pair(ansflow,anscost); } int main() { #ifdef WIN32 freopen("a.in","r",stdin); #endif memset(head,-1,sizeof(head)); N=read(),M=read(),S=read(),T=read(); for(int i=1;i<=M;i++) { int x=read(),y=read(),f=read(),z=read(); AddEdge(x,y,f,z); } Pair ans=Dij(); printf("%d %d",ans.fi,ans.se); return 0; }

洛谷P3381 【模板】最小費用最大流(dijstra費用流)