[CODEVS1917] 深海机器人问题(最小费用最大流)
【问题分析】
最大费用最大流问题。
【建模方法】
把网格中每个位置抽象成网络中一个节点,建立附加源S汇T。
1、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为1,费用为该边价值的有向边。
2、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为无穷大,费用为0的有向边。
3、从S到每个出发点i连接一条容量为该点出发的机器人数量,费用为0的有向边。
4、从每个目标点i到T连接一条容量为可以到达该点的机器人数量,费用为0的有向边。
求最大费用最大流,最大费用流值就采集到的生物标本的最高总价值。
【建模分析】
这个问题可以看做是多出发点和目的地的网络运输问题。每条边的价值只能计算一次,容量限制要设为1。同时还将要连接上容量不限,费用为0的重边。由于“多个深海机器人可以在同一时间占据同一位置”,所以不需限制点的流量,直接求费用流即可。
吐槽:这出题人语文tm谁教的,输入看了我老半天
只需要知道权值不在点,而到了边上,而起点和终点变成了多个,起点和终点都有容量限制。
反而使题目变简单了(因为不再有没有权值的边,而且权值在边上比权值在点上多了一个好处——不用拆点)。
——代码
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define INF 1e9 6 #define N 1000001 7 #define min(x, y) ((x) < (y) ? (x) : (y)) 8 9 int a, b, n, m, cnt, s, t; 10 int dis[N], pre[N]; 11 int head[N], to[N << 1], val[N << 1], cost[N << 1], next[N << 1]; 12 bool vis[N]; 13 14 inline int read() 15 { 16 int x = 0, f = 1; 17 char ch = getchar(); 18 for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1; 19 for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; 20 return x * f; 21 } 22 23 inline int hash(int x, int y) 24 { 25 return x * m + y; 26 } 27 28 inline void add2(int x, int y, int z, int c) 29 { 30 to[cnt] = y; 31 val[cnt] = z; 32 cost[cnt] = c; 33 next[cnt] = head[x]; 34 head[x] = cnt++; 35 } 36 37 inline void add(int x, int y, int z, int c) 38 { 39 add2(x, y, z, c); 40 add2(y, x, 0, -c); 41 } 42 43 inline bool spfa() 44 { 45 int i, u, v; 46 std::queue <int> q; 47 memset(vis, 0, sizeof(vis)); 48 memset(pre, -1, sizeof(pre)); 49 memset(dis, 127 / 3, sizeof(dis)); 50 q.push(s); 51 dis[s] = 0; 52 while(!q.empty()) 53 { 54 u = q.front(), q.pop(); 55 vis[u] = 0; 56 for(i = head[u]; i ^ -1; i = next[i]) 57 { 58 v = to[i]; 59 if(val[i] && dis[v] > dis[u] + cost[i]) 60 { 61 dis[v] = dis[u] + cost[i]; 62 pre[v] = i; 63 if(!vis[v]) 64 { 65 q.push(v); 66 vis[v] = 1; 67 } 68 } 69 } 70 } 71 return pre[t] ^ -1; 72 } 73 74 inline int dinic() 75 { 76 int i, d, sum = 0; 77 while(spfa()) 78 { 79 d = INF; 80 for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) d = min(d, val[i]); 81 for(i = pre[t]; i ^ -1; i = pre[to[i ^ 1]]) 82 { 83 val[i] -= d; 84 val[i ^ 1] += d; 85 } 86 sum += dis[t] * d; 87 } 88 return sum; 89 } 90 91 int main() 92 { 93 int i, j, k, x, y; 94 a = read(); 95 b = read(); 96 n = read(); 97 m = read(); 98 n++, m++; 99 s = 0, t = N - 1; 100 memset(head, -1, sizeof(head)); 101 for(i = 0; i < n; i++) 102 for(j = 1; j < m; j++) 103 { 104 x = read(); 105 add(hash(i, j), hash(i, j + 1), 1, -x); 106 add(hash(i, j), hash(i, j + 1), INF, 0); 107 } 108 for(j = 1; j <= m; j++) 109 for(i = 0; i < n - 1; i++) 110 { 111 x = read(); 112 add(hash(i, j), hash(i + 1, j), 1, -x); 113 add(hash(i, j), hash(i + 1, j), INF, 0); 114 } 115 while(a--) 116 { 117 k = read(); 118 x = read(); 119 y = read(); 120 add(s, hash(x, y + 1), k, 0); 121 } 122 while(b--) 123 { 124 k = read(); 125 x = read(); 126 y = read(); 127 add(hash(x, y + 1), t, k, 0); 128 } 129 printf("%d\n", -dinic()); 130 return 0; 131 }