[题解] PowerOJ 1755 深海机器人问题 (最大费用最大流)
- 传送门 -
https://www.oj.swust.edu.cn/problem/show/1755
Time Limit: 1000 MS Memory Limit: 65536 KB
Total Submit: 65 Accepted: 39 Page View: 569
Description
深海资源考察探险队的潜艇将到达深海的海底进行科学考察。潜艇内有多个深海机器 人。潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动。深海机器人在移动中还 必须沿途采集海底生物标本。沿途生物标本由最先遇到它的深海机器人完成采集。每条预定 路径上的生物标本的价值是已知的,而且生物标本只能被采集一次。本题限定深海机器人只 能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一 位置。 «编程任务: 用一个PxQ 网格表示深海机器人的可移动位置。西南角的坐标为(0,0),东北角的坐 标为 (Q,P)。 给定每个深海机器人的出发位置和目标位置,以及每条网格边上生物标本的价值。计算 深海机器人的最优移动方案,使深海机器人到达目的地后,采集到的生物标本的总价值最高。
Input
由文件input.txt提供输入数据。文件的第1 行为深海机器人的出发位置数a,和目的地 数b,第2 行为P和Q 的值。接下来的P+1 行,每行有Q 个正整数,表示向东移动路径上 生物标本的价值,行数据依从南到北方向排列。再接下来的Q+1 行,每行有P 个正整数, 表示向北移动路径上生物标本的价值,行数据依从西到东方向排列。接下来的a行,每行有 3 个正整数k,x,y,表示有k个深海机器人从(x,y)位置坐标出发。再接下来的b行,每行有3 个正整数r,x,y,表示有r个深海机器人可选择(x,y)位置坐标作为目的地。
Output
程序运行结束时,将采集到的生物标本的最高总价值输出到文件output.txt中。
1 1
2 2
1 2 3
4 5 6
7 2 8
10 9 3
2 0 0
2 2 2
42
Source
- 思路 -
把两点间的边一分为二, 一条容量为 1 而费用为边权, 一条容量为 inf 而费用为 0.
然后求最大费用最大流.
注意这题的行列分布有点儿迷.
P 指最大行数. Q 指最大列数(从 0 开始).
然后最后的出发点和到达点 (x, y) 指的是 x 行 y 列, 图上的右上点 (Q, P) 指的应该是 P 行 Q 列.
细节见代码.
- 代码 -
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1050;
const int M = 105000;
const int inf = 0x3f3f3f3f;
int CT[M], V[M], TO[M], NXT[M];
int HD[N], VIS[N], DIS[N], PRE[N];
int map[20][20];
int n, m, s, t, ss, tt, sz;
queue<int> q;
int mk(int x, int y) {
return x * (m + 1) + y + 1; //记录点什么的细致细致!!!
}
void add(int x, int y, int z, int c) {
TO[sz] = y; NXT[sz] = HD[x]; HD[x] = sz;
V[sz] = z; CT[sz++] = c;
TO[sz] = x; NXT[sz] = HD[y]; HD[y] = sz;
V[sz] = 0; CT[sz++] = -c;
}
bool spfa() {
memset(DIS, 0xc0, sizeof (DIS));
DIS[ss] = 0;
q.push(ss);
PRE[tt] = -1;
while (!q.empty()) {
int u = q.front();
q.pop();
VIS[u] = 0;
for (int i = HD[u]; i != -1; i = NXT[i]) {
int v = TO[i];
if (V[i] > 0 && DIS[v] < DIS[u] + CT[i]) {
DIS[v] = DIS[u] + CT[i];
PRE[v] = i;
if (!VIS[v]) {
VIS[v] = 1;
q.push(v);
}
}
}
}
return PRE[tt] != -1; //注意判断方式
}
int mcmf() {
int cost = 0;
while (spfa()) {
int tmp = inf;
for (int i = tt; i != ss; i = TO[PRE[i]^1])
if (tmp > V[PRE[i]]) tmp = V[PRE[i]];
for (int i = tt; i != ss; i = TO[PRE[i]^1]) {
V[PRE[i]] -= tmp;
V[PRE[i]^1] += tmp;
}
cost += tmp * DIS[tt];
}
return cost;
}
int main() {
memset(HD, -1, sizeof (HD));
scanf("%d%d%d%d", &s, &t, &n, &m);
ss = 0, tt = (n + 1) * (m + 1) + 1;
int a, x, y;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j < m; ++j) {
scanf("%d", &x);
add(mk(i, j), mk(i, j + 1), 1, x);
add(mk(i, j), mk(i, j + 1), inf, 0);
}
}
for (int i = 0; i <= m; ++i) {
for (int j = 0; j < n; ++j) {
scanf("%d", &x);
add(mk(j, i), mk(j + 1, i), 1, x);
add(mk(j, i), mk(j + 1, i), inf, 0);
}
}
for (int i = 1; i <= s; ++i) {
scanf("%d%d%d", &a, &x, &y);
add(ss, mk(x, y), a, 0);
}
for (int i = 1; i <= t; ++i) {
scanf("%d%d%d", &a, &x, &y);
add(mk(x, y), tt, a, 0);
}
printf("%d\n", mcmf());
return 0;
}