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 }

 

你可能感兴趣的:(OJ)