hoj 2715 (费用流 拆点)

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

将每个格子 i 拆成两个点 i’, i’’并加边(i’, i’’, 1, -Vi), (i’, i’’, ∞, 0), (s, i’, ∞, 0); 控制只有一次能取到宝物。

对相邻的四个格子 j, Hi > Hj 则加边(i’’, j’, ∞, 0);

若格子 i 在边界上则加边(i’’, t, ∞, 0)。

限制增广次数小于等于 K 求最小费用流即可。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <cmath>
  7 
  8 using namespace std;
  9 
 10 const int maxn = 505;
 11 const int maxm = 2000;
 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     int mcmf(int S, int T, int kt)
 63     {
 64         sumFlow = 0;
 65         int minFlow = 0, minCost = 0;
 66         while (spfa(S, T) && (kt--))
 67         {
 68             minFlow = inf + 1;
 69             for (int i = pre[T]; i + 1; i = pre[ p[i ^ 1].v ])
 70                 minFlow = min(minFlow, 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         }
 79         return minCost;
 80     }
 81     void build(int nt, int kt)
 82     {
 83         int nnt = nt * nt;
 84         init(nnt * 2 + 1);
 85         int val[53][53], height[53][53];
 86         memset(val, 0x3f, sizeof(val));
 87         memset(height, 0x3f, sizeof(height));
 88         for (int i = 1; i <= nt; ++i)
 89             for (int j = 1; j <= nt; ++j)
 90                 scanf("%d", &val[i][j]);
 91         for (int i = 1; i <= nt; ++i)
 92             for (int j = 1; j <= nt; ++j)
 93                 scanf("%d", &height[i][j]);
 94         for (int i = 1; i <= nt; ++i)
 95             for (int j = 1; j <= nt; ++j)
 96             {
 97                 int pos = nt * (i - 1) + j;
 98                 addEdge(0, pos, inf, 0);
 99                 addEdge(pos, pos + nnt, 1,-val[i][j]);
100                 addEdge(pos, pos + nnt, inf,0);
101                 if (i == 1 || i == nt || j == 1 || j == nt)
102                     addEdge(pos + nnt, n, inf, 0);
103                 if (height[i][j] > height[i][j - 1])
104                     addEdge(pos + nnt, pos - 1, inf, 0);
105                 if (height[i][j] > height[i][j + 1])
106                     addEdge(pos + nnt, pos + 1, inf, 0);
107                 if (height[i][j] > height[i - 1][j])
108                     addEdge(pos + nnt, pos - nt, inf, 0);
109                 if (height[i][j] > height[i + 1][j])
110                     addEdge(pos + nnt, pos + nt, inf, 0);
111             }
112     }
113     void solve(int nt, int kt)
114     {
115         build(nt, kt);
116         printf("%d
", - mcmf(0, n, kt));
117     }
118 }my;
119 int main()
120 {
121     int tcase, n, k;
122     scanf("%d", &tcase);
123     while (tcase--)
124     {
125         scanf("%d%d", &n, &k);
126         my.solve(n, k);
127     }
128     return 0;
129 }
原文地址:https://www.cnblogs.com/Missa/p/3266188.html