1. 程式人生 > >HOJ - 2543最小費用流

HOJ - 2543最小費用流

memset max class cap 個數 hoj else hit clu

題目鏈接:http://acm.hit.edu.cn/hoj/problem/view?id=2543

這個題目挺有意思。

自己扣了一會兒,發現圖挺好建,就把(u,v,f,w) 拆成(u,v,f,0)和(u,v,INF,w)就好了。但是在枚舉石頭時,我想的是二分石頭個數,就需要每次重新建圖,把邊的信息提前保存下來,發現有點麻煩。

看題解說,利用連續最短路算法,每次找一條最小費用路並盡可能多的增廣,直到剩余錢數不夠再運一個石頭為止。就是直接在模板裏面改,太方便了。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4
#include <vector> 5 #include <queue> 6 #include <algorithm> 7 using namespace std; 8 const int maxn = 2e3; 9 const int INF = 1e9; 10 int vis[maxn],dist[maxn]; 11 int tot,head[maxn]; 12 int pv[maxn],pe[maxn]; 13 typedef long long ll; 14 struct edge 15 { 16 int to,pre,cap,cost;
17 }e[100000]; 18 void init() 19 { 20 tot = 0; 21 memset(head,-1,sizeof(head)); 22 } 23 void add(int from,int to,int cap,int cost) 24 { 25 e[tot].pre = head[from]; 26 e[tot].to = to; 27 e[tot].cap = cap; 28 e[tot].cost = cost; 29 head[from] = tot++; 30 } 31 void addedge(int
from,int to,int cap,int cost) 32 { 33 add(from,to,cap,cost); 34 add(to,from,0,-cost); 35 } 36 int n,m; 37 ll c,p; 38 int ans = 0; 39 int min_cost_flow(int s,int t,int f,int& max_flow) 40 { 41 int ret = 0; 42 while(f>0) 43 { 44 memset(vis,0,sizeof(vis)); 45 for(int i=0;i<maxn;i++) dist[i] = INF; 46 dist[s] = 0; 47 queue<int> q; 48 q.push(s); 49 while(!q.empty()) 50 { 51 int v = q.front(); q.pop(); 52 vis[v] = 0; 53 for(int i=head[v];i>=0;i=e[i].pre) 54 { 55 int to = e[i].to,cap = e[i].cap,cost = e[i].cost; 56 if(cap>0&&dist[to]>dist[v]+cost) 57 { 58 pv[to] = v,pe[to] = i; 59 dist[to] = dist[v] + cost; 60 if(!vis[to]) q.push(to); 61 vis[to] = 1; 62 } 63 } 64 } 65 if(dist[t]==INF) return ret; 66 ///當所有邊的流量都流凈後,即沒有殘余網絡,返回。 67 int d = f; 68 for(int v=t;v!=s;v=pv[v]) 69 { 70 d = min(d,e[pe[v]].cap); 71 } 72 f -= d; 73 max_flow += d; 74 ret += d*dist[t]; ///走一單位就消耗dist[t] 75 for(int v=t;v!=s;v=pv[v]) 76 { 77 e[pe[v]].cap -= d; 78 e[pe[v]^1].cap += d; 79 } 80 81 ///最有意思,在模板裏面修改,利用增廣路不斷去減少錢數 82 if(c>=((ll)d*p+(ll)d*dist[t])) 83 { 84 c -= ((ll)d*p+(ll)d*dist[t]); 85 ans += d; 86 } 87 else 88 { 89 ans += (c/((ll)dist[t]+(ll)p)); ///算算單獨能運幾塊石頭 90 break; 91 } 92 } 93 return ret; 94 } 95 int main() 96 { 97 int T;scanf("%d",&T); 98 while(T--) 99 { 100 init(); //別忘寫 101 scanf("%d %d %lld %lld",&n,&m,&c,&p); 102 int u,v,f,w; 103 for(int i=1;i<=m;i++) 104 { 105 scanf("%d %d %d %d",&u,&v,&f,&w); 106 addedge(u,v,f,0); 107 addedge(v,u,f,0); 108 addedge(u,v,INF,w); 109 addedge(v,u,INF,w); 110 } 111 int max_flow = 0; 112 ans = 0; 113 min_cost_flow(0,1,INF,max_flow); 114 printf("%d\n",ans); 115 } 116 return 0; 117 }

HOJ - 2543最小費用流