LUOGU 4012 深海机器人问题 网络流24题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/91357969

title

LUOGU 4012
题目描述

深海资源考察探险队的潜艇将到达深海的海底进行科学考察。
潜艇内有多个深海机器人。潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动。
深海机器人在移动中还必须沿途采集海底生物标本。沿途生物标本由最先遇到它的深海机器人完成采集。
每条预定路径上的生物标本的价值是已知的,而且生物标本只能被采集一次。
本题限定深海机器人只能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一位置。
用一个 P × Q P\times Q 网格表示深海机器人的可移动位置。西南角的坐标为 (0,0),东北角的坐标为 (Q,P) 。
在这里插入图片描述
给定每个深海机器人的出发位置和目标位置,以及每条网格边上生物标本的价值。
计算深海机器人的最优移动方案, 使深海机器人到达目的地后,采集到的生物标本的总价值最高。

输入输出格式
输入格式:

文件的第 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) 位置坐标作为目的地。
a行和b行输入时横纵坐标要反过来骗人的

输出格式:

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

输入输出样例
输入样例#1:

1 1
2 2
1 2
3 4
5 6
7 2
8 10
9 3
2 0 0
2 2 2

输出样例#1:

42

说明

1 P , Q 15 1\leq P,Q\leq15
1 a 4 1\leq a\leq 4
1 b 6 1\leq b\leq 6

analysis

有人说这道题是BZOJ 1001 狼抓兔子的升级版,在我看来,的确是,思维难度肯定是上升了些,但是它的省选级别难度一大半估计是因为它的语言描述。

我们在两两格子之间连两条边:一条边容量为 1 1 ,代价为 权值 ,另一条容量为 I N F INF ,代价为 0 0

然后对于每个起点,从 s 源点s 连一条容量为 k i k_i 的边。终点同理。

哦,就没了,有些套路吧,但是因为他的语言描述,搞得我对这题描述的坐标一头懵,半天才看懂真的是被恶心死,要不然也不想这么吐槽

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10,inf=0xcfcfcfcf,INF=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

template<typename T>inline void write(T x)
{
    if (!x) { putchar('0'); return ; }
    if (x<0) putchar('-'), x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) putchar(ch[num--]);
}

int ver[maxn<<1],edge[maxn<<1],Next[maxn<<1],cost[maxn<<1],head[maxn],len=1;
inline void add(int x,int y,int z,int c)
{
    ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;
    ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;
}

int s,t;
int dist[maxn],incf[maxn],pre[maxn];
bool vis[maxn];
inline bool spfa()
{
    memset(dist,0xcf,sizeof(dist));
    memset(vis,0,sizeof(vis));
    queue<int>q;q.push(s);
    dist[s]=0,vis[s]=1,incf[s]=1<<30;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for (int i=head[x]; i; i=Next[i])
        {
            if (!edge[i]) continue;
            int y=ver[i];
            if (dist[y]<dist[x]+cost[i])
            {
                dist[y]=dist[x]+cost[i];
                incf[y]=min(incf[x],edge[i]);
                pre[y]=i;
                if (!vis[y]) q.push(y),vis[y]=1;
            }
        }
    }
    if (dist[t]==inf) return false;
    else return true;
}

long long maxflow,ans;
inline void update()
{
    int x=t;
    while (x!=s)
    {
        int i=pre[x];
        edge[i]-=incf[t];
        edge[i^1]+=incf[t];
        x=ver[i^1];
    }
    maxflow+=incf[t];
    ans+=dist[t]*incf[t];
}

int main()
{
	int a,b,P,Q,id[16][16];
	read(a);read(b);read(P);read(Q);
    for (int cnt=0,i=0; i<=P; ++i)
        for (int j=0; j<=Q; ++j) id[i][j]=++cnt;
    s=(P+1)*(Q+1)+1,t=s+1;
    for (int i=0; i<=P; ++i)
        for (int j=0,x; j<Q; ++j) read(x),add(id[i][j],id[i][j+1],1,x),add(id[i][j],id[i][j+1],INF,0);

    for (int j=0; j<=Q; ++j)
        for (int i=0,x; i<P; ++i) read(x),add(id[i][j],id[i+1][j],1,x),add(id[i][j],id[i+1][j],INF,0);

    for (int k,x,y; a; --a) read(k),read(x),read(y),add(s,id[x][y],k,0);
    for (int r,x,y; b; --b) read(r),read(x),read(y),add(id[x][y],t,r,0);

    while (spfa()) update();
    write(ans),puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/91357969