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\n", - 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 }

 

你可能感兴趣的:(OJ)