HOJ - 2543最小费用流

题目链接: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 }

 

posted @ 2017-09-30 11:32  卷珠帘  阅读(213)  评论(0编辑  收藏  举报