网络流24题(二十)

网络流24题(二十)

二十、深海机器人问题

题目描述

深海资源考察探险队的潜艇将到达深海的海底进行科学考察。

潜艇内有多个深海机器人。潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动。

深海机器人在移动中还必须沿途采集海底生物标本。沿途生物标本由最先遇到它的深海机器人完成采集。

每条预定路径上的生物标本的价值是已知的,而且生物标本只能被采集一次。

本题限定深海机器人只能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一位置。

用一个\(P\times Q\) 网格表示深海机器人的可移动位置。西南角的坐标为 \((0,0)\),东北角的坐标为 \((Q,P)\)

给定每个深海机器人的出发位置和目标位置,以及每条网格边上生物标本的价值。

计算深海机器人的最优移动方案, 使深海机器人到达目的地后,采集到的生物标本的总价值最高。

输入格式

文件的第 1 行为深海机器人的出发位置数 a,和目的地数 b 。

第 2 行为 P 和 Q 的值。

接下来的 P+1 行,每行有 Q 个正整数,表示向东移动路径上生物标本的价值,行数据依从南到北方向排列。

再接下来的 Q+1 行,每行有 P 个正整数,表示向北移动路径上生物标本的价值,行数据依从西到东方向排列。

接下来的 行,每行有 3 个正整数 k,x,y,表示有 k 个深海机器人从 (x,y) 位置坐标出发。

再接下来的 b 行,每行有 3 个正整数 r,x,y ,表示有 r 个深海机器人可选择 (x,y) 位置坐标作为目的地。

输出格式

输出采集到的生物标本的最高总价值.

题解

模型

最大费用最大流

建图

每个点向东和北连接两条边,一条流量1,费用是题设给出的边权的负值,一条流量无穷,费用为0.原因是一条边可以走多次,但是只有一次会有费用。
设置超级源点S和超级汇点T。
S和每个起点连边,容量为k,费用为0,每个终点与T连边。容量为r,费用为0.
跑最大费用最大流即可。

代码

#include <iostream>
#include <queue>
#include <map>
#define ll long long
const ll N = 5e3+50,M = 5e4+50;
const ll inf = 0x3f3f3f3f;
using namespace std;
ll head[N],cnt = 1;
//将EK的bfs变为spfa
struct Edge{
    ll to,w,cost,nxt;
}edge[M*2];
void add(ll u,ll v,ll w,ll c){
    edge[++cnt] = {v,w,c,head[u]};
    head[u] = cnt;
}
void  add2(ll u,ll v,ll w,ll cost){
    add(u,v,w,cost);
    add(v,u,0,-cost);
}
ll s,t,dis[N],cur[N];
bool inq[N],vis[N];
queue<ll>Q;
bool spfa(){
    while(!Q.empty()) Q.pop();
    copy(head,head+N,cur);
    fill(dis,dis+N,inf);
    dis[s] = 0;
    Q.push(s);
    while(!Q.empty()){
        ll p = Q.front();
        Q.pop();
        inq[p] = false;
        for(ll e = head[p];e;e = edge[e].nxt){
            ll to = edge[e].to,vol = edge[e].w;
            if(vol > 0 && dis[to]>dis[p]+edge[e].cost){
                dis[to] = dis[p] + edge[e].cost;
                if(!inq[to]){
                    Q.push(to);
                    inq[to] = true;
                }
            }
        }
    }
    return dis[t] != inf;
}
ll dfs(ll p = s,ll flow = inf){
    if(p == t) return flow;
    vis[p] = true;
    ll rmn = flow;
    for(ll eg = cur[p];eg && rmn;eg = edge[eg].nxt){
        cur[p] = eg;
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol > 0 && !vis[to]&&dis[to] == dis[p]+edge[eg].cost){
            ll c = dfs(to,min(vol,rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg^1].w += c;
        }
    }
    vis[p] = false;
    return flow-rmn;
}
ll maxflow = 0,mincost = 0;
void dinic(){
    while(spfa()){
        ll flow = dfs();
        maxflow += flow;
        mincost += dis[t]*flow;
    }
}
ll a,b,p,q;
map<pair<ll,ll>,ll>ma;
int main() {
    ios::sync_with_stdio(false);
    cin>>a>>b>>p>>q;
    ll cnt0 = 0;
    for(ll i = 0;i <= p;i++){
        for(ll j = 0;j <= q;j++){
            ma[{i,j}] = ++cnt0;
        }
    }
    for(ll i = 0;i <= p;i++){
        for(ll j = 1;j <= q;j++){
            ll x;cin>>x;
            add2(ma[{i,j-1}],ma[{i,j}],inf,0);
            add2(ma[{i,j-1}],ma[{i,j}],1,-1*x);
        }
    }
    for(ll j = 0;j <= q;j++){
        for(ll i = 1;i <= p;i++){
            ll x;cin>>x;
            add2(ma[{i-1,j}],ma[{i,j}],inf,0);
            add2(ma[{i-1,j}],ma[{i,j}],1,-1*x);
        }
    }
    s = 0,t = cnt0+1;
    for(ll i = 1;i <= a;i++){
        ll k,x,y;cin>>k>>x>>y;
        add2(s,ma[{x,y}],k,0);
    }
    for(ll i = 1;i <= b;i++){
        ll k,x,y;cin>>k>>x>>y;
        add2(ma[{x,y}],t,k,0);
    }
    dinic();
    cout<<-1*mincost<<endl;
    return 0;
}
posted @ 2021-10-30 19:16  Paranoid5  阅读(20)  评论(0编辑  收藏  举报