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 }