[题解] PowerOJ 1755 深海机器人问题 (最大费用最大流)

- 传送门 -

 https://www.oj.swust.edu.cn/problem/show/1755

# 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

线性规划与网络流24题

 

- 思路 -

 把两点间的边一分为二, 一条容量为 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;
}
posted @ 2017-08-25 20:55  lstttt  阅读(215)  评论(0编辑  收藏  举报