【模板】最小費用最大流


題目描述

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

輸入輸出格式

輸入格式:

 

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

樣例說明:

如圖,最優方案如下:

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

思路:費用流

因為要注意費用的問題,所以用SPFA找費用最小的增廣路,不要用Dijkstra(因為有負邊權)(然而一般情況下SPFA更好寫,所以這個警告是廢話);

然后增廣ap()。

幾個注意的地方:

反邊費用為其對應邊的相反數;

隊列首尾指針記得清零;(RE了50%左右)

有一種常(la)數(ji)級優化技巧叫先留個坑,反邊隨用隨建。(優化程度達不到O()*0.5,但是夠用,而且很好實現);

代碼實現:

 1 #include<cstdio>
 2 #include<cstring>
 3 #define maxn 5010
 4 #define maxm 100010
 5 #define maxt 2139062143
 6 int n,m,s,t,nflow,nfee,flow,fee;
 7 int a,b,c,d;
 8 long long la,lb;
 9 int h[maxn],hs=1;
10 struct edge{int s,n,w,f;}e[maxm];
11 int w[maxn];
12 int p[maxn][2];
13 int q[maxm],head,tail;
14 int min(int x,int y){return x<y?x:y;}
15 int spfa(){
16     memset(w,0x7f,sizeof(w));
17     head=tail=0;
18     q[head++]=s,w[s]=0;
19     while(head>tail){
20         a=q[tail++];
21         for(int i=h[a];i;i=e[i].n)
22         if(e[i].w){
23             la=e[i].f,lb=w[a],la+=lb,lb=w[e[i].s];
24             if(la<lb){
25                 w[e[i].s]=la;
26                 p[e[i].s][0]=i;
27                 p[e[i].s][1]=a;
28                 q[head++]=e[i].s;
29             }
30         }
31     }
32     return w[t];
33 }
34 int ap(int k,int v){
35     if(k==s) return v;
36     int ret=ap(p[k][1],min(e[p[k][0]].w,v));
37     if(!e[p[k][0]^1].f) e[p[k][0]^1]=(edge){p[k][1],h[k],0,-e[p[k][0]].f},h[k]=p[k][0]^1;
38     e[p[k][0]].w-=ret;
39     e[p[k][0]^1].w+=ret;
40     return ret;
41 }
42 bool Mcmf(){
43     nfee=spfa();
44     if(nfee==maxt) return false;
45     nflow=ap(t,maxt);
46     flow+=nflow;
47     fee+=nflow*nfee;
48     return true;
49 }
50 int main(){
51     scanf("%d%d%d%d",&n,&m,&s,&t);
52     for(int i=1;i<=m;i++){
53         scanf("%d%d%d%d",&a,&b,&c,&d);
54         e[++hs]=(edge){b,h[a],c,d},h[a]=hs++;
55     }
56     while(Mcmf());
57     printf("%d %d\n",flow,fee);
58     return 0;
59 }
初版(1930ms)

代碼重構:

struct換為數組;(更快)

函數重構;(更優美)

結果:916ms

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=1e4+10;
 4 const int maxm=1e5+10;
 5 const int maxt=2139062143;
 6 inline int min_(int x,int y){return x<y?x:y;}
 7 int n,m,s,t,nflow,nfee,flow,fee;
 8 int a,b,c,d;
 9 int h[maxn],hs=1;
10 int e_q[maxm],e_z[maxm],e_n[maxm],e_w[maxm],e_f[maxm];
11 int add(int q,int z,int k,int w,int f){e_q[k]=q,e_z[k]=z,e_n[k]=h[q],e_w[k]=w,e_f[k]=f,h[q]=k;}
12 int q[maxm],head,tail;
13 int w[maxn],p[maxn];
14 bool v[maxn];
15 int ap(int k,int v){
16     if(k==s) return v;
17     int ret=ap(e_q[p[k]],min_(v,e_w[p[k]]));
18     if(!e_f[p[k]^1]) add(k,e_q[p[k]],p[k]^1,0,-e_f[p[k]]);
19     e_w[p[k]]-=ret,e_w[p[k]^1]+=ret;
20     return ret;
21 } 
22 void Mcmf(){
23     while(1){
24         memset(w,0x7f,sizeof(w));
25         memset(v,0,sizeof(v));
26         head=tail=w[s]=0;
27         q[head++]=s,v[s]=1;
28         while(head>tail){
29             a=q[tail++],v[a]=0;
30             for(int i=h[a];i;i=e_n[i])
31             if(0ll+e_f[i]+w[a]<w[e_z[i]]&&e_w[i]){
32                 p[e_z[i]]=i;
33                 w[e_z[i]]=e_f[i]+w[a];
34                 if(!v[e_z[i]]) q[head++]=e_z[i],v[e_z[i]]=1;
35             }
36         }
37         if(w[t]==maxt) break;
38         nflow=ap(t,maxt);
39         flow+=nflow;
40         fee+=nflow*w[t];
41     }
42 }
43 int main(){
44     scanf("%d%d%d%d",&n,&m,&s,&t);
45     for(int i=1;i<=m;i++){
46         scanf("%d%d%d%d",&a,&b,&c,&d);
47         ++hs,add(a,b,hs,c,d),hs++;
48     }
49     Mcmf();
50     printf("%d %d\n",flow,fee);
51     return 0;
52 }

題目來源:洛谷


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM