hoj 2543 (费用流 拆边)

http://acm.hit.edu.cn/hoj/problem/view?id=2543

1.将原图中的每条边(u, v)拆成两条:(u, v, Ci, 0), (u, v, ∞, Ei)

2.购买的每个石头的费用P加一条 (S, 1, inf, P)的边。

3.总的能够花费的费用C可以在我们求最小费用路的时候判断。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 #include <algorithm>
  6 #include <cmath>
  7 
  8 using namespace std;
  9 typedef long long LL;
 10 const int maxn = 1e3 + 5;
 11 const int maxm = 1e5+ 5;
 12 const int inf = 0x3f3f3f3f;
 13 
 14 struct MCMF
 15 {
 16     struct Edge
 17     {
 18         int v, c, w, next;
 19     }p[maxm << 1];
 20     int e, head[maxn], dis[maxn], pre[maxn], cnt[maxn], sumFlow, n;
 21     bool vis[maxn];
 22     void init(int nt)
 23     {
 24         e = 0, n = nt;
 25         memset(head, -1, sizeof(head[0]) * (n + 2) );
 26     }
 27     void addEdge(int u, int v, int c, int w)
 28     {
 29         p[e].v = v; p[e].c = c; p[e].w = w; p[e].next = head[u]; head[u] = e++;
 30         swap(u, v);
 31         p[e].v = v; p[e].c = 0; p[e].w = -w; p[e].next = head[u]; head[u] = e++;
 32     }
 33     bool spfa(int S, int T)
 34     {
 35         queue <int> q;
 36         for (int i = 0; i <= n; ++i)
 37             vis[i] = cnt[i] = 0, pre[i] = -1, dis[i] = inf;
 38         vis[S] = 1, dis[S] = 0;
 39         q.push(S);
 40         while (!q.empty())
 41         {
 42             int u = q.front(); q.pop();
 43             vis[u] = 0;
 44             for (int i = head[u]; i + 1; i = p[i].next)
 45             {
 46                 int v = p[i].v;
 47                 if (p[i].c && dis[v] > dis[u] + p[i]. w)
 48                 {
 49                     dis[v] = dis[u] + p[i].w;
 50                     pre[v] = i;
 51                     if (!vis[v])
 52                     {
 53                         q.push(v);
 54                         vis[v] = 1;
 55                         if (++cnt[v] > n) return 0;
 56                     }
 57                 }
 58             }
 59         }
 60         return dis[T] != inf;
 61     }
 62     void mcmf(int S, int T, int ct)
 63     {
 64         sumFlow = 0;
 65         LL minFlow = 0, minCost = 0;
 66         while (spfa(S, T))
 67         {
 68             minFlow = inf + 1;
 69             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
 70                 minFlow = min(minFlow,(LL)p[i].c);
 71             sumFlow += minFlow;
 72             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
 73             {
 74                 p[i].c -= minFlow;
 75                 p[i ^ 1].c == minFlow;
 76             }
 77             minCost += dis[T] * minFlow;
 78             if (minCost > ct)
 79             {
 80                 sumFlow -= ceil((minCost - ct) * 1.0 / dis[T]);
 81                 break;
 82             }
 83         }
 84     }
 85     void build(int nt, int mt, int ct, int pt)
 86     {
 87         init(nt);
 88         int u, v, c, w;
 89         addEdge(0, 1, inf, pt);
 90         while (mt--)
 91         {
 92             scanf("%d%d%d%d", &u, &v, &c, &w);
 93             u++, v++;
 94             addEdge(u, v, c, 0); addEdge(u, v, inf, w);
 95             swap(u, v);
 96             addEdge(u, v, c, 0); addEdge(u, v, inf, w);
 97         }
 98     }
 99     void solve(int nt, int mt, int ct, int pt)
100     {
101         build(nt, mt, ct, pt);
102         mcmf(0, 2, ct);
103         printf("%d\n", sumFlow);
104     }
105 }my;
106 int main()
107 {
108     int tcase, n, m, c, p;
109     scanf("%d", &tcase);
110     while (tcase--)
111     {
112         scanf("%d%d%d%d",&n, &m, &c, &p);
113         my.solve(n, m, c, p);
114     }
115     return 0;
116 }

 

posted @ 2013-08-18 12:39  Missa  阅读(293)  评论(0编辑  收藏  举报