【网络流24题】洛谷P4012 深海机器人问题

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88069485

D e s c r i p t i o n Description

在一个 n × m n\times m 的矩阵中,每个点都有自己的权值

a a 个起点, b b 个终点

每个起点都有 k a i ka_i 个机器人,每个终点可以到达 k b i kb_i 个机器人

机器人只能向右或向上走,当机器人经过某个点时可以取走当前点的权值(只能取一次

求到达终点的机器人的最大权值总和

数据范围:
n , m 15 n,m\leq15
a 4 a\leq 4
b 6 b\leq 6


S o l u t i o n Solution

鸣谢 w y c wyc 大佬的讲解,算是比较能弄懂这题的建图了,一眼就看出正解的他太强啦%%%

根据数据范围和标签可以看出这题是一道网络流

容易看出这道题的模型有点类似于传纸条,因为格子的值是非负的,所以我显然越多机器人到达时越好的,这就是一个最大流。

现在我们要在此基础上使得权值总和最大,也就是一个最大费用最大流了

现在我们考虑费用

扫描二维码关注公众号,回复: 5623333 查看本文章

启动机器人是无代价的,日常费用0

主要考虑取走这个问题,由于每个只能取一次,所以容量为1,代价为其价值,但是如果单纯这样建是错误的,因为它取走之后还可以继续走,所以还要建一条“经过点”,容量为无穷大(无限经过),代价为0(经过当然没有代价了啦)

其它的日常网络流啦

依照网络流的套路,我们把费用取负,然后跑最小费用最大流即可

如图(真的良心绘图):图片绘图网址


C o d e Code

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define id(i,j) ((i-1)*m+j)
#define M 400001
using namespace std;int f,n,m,s,t,ans1,ans2,a,b,k,x,y;char c;
int read()//输入优化
{
    f=0;
    while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
struct node{int next,to,w,g;}e[M<<1];
int dis[M],l[M],tot,pos[M];
bool vis[M];
void add(int u,int v,int w,int c)
{
    e[tot]=(node){l[u],v,w,c};l[u]=tot++;
    e[tot]=(node){l[v],u,0,-c};l[v]=tot++;
    return;
}
bool spfa()
{
    fill(dis+1,dis+1+t,50234567);
    memset(vis,0,sizeof(vis));
    queue<int>q;q.push(s);dis[s]=0;vis[s]=true;
    while(q.size())
    {
        int x=q.front();q.pop();vis[x]=true;
        for(int i=l[x];~i;i=e[i].next)
        {
            int y=e[i].to,w=e[i].g;
            if(e[i].w&&dis[y]>dis[x]+w)
            {
                dis[y]=dis[x]+w;
                pos[y]=i;
                if(!vis[y]) q.push(y),vis[y]=true;
            }
        }
        vis[x]=false;
    }
    return dis[t]<50234567;
}
void updata()
{
    int x=t;
    while(x!=s)
    {
        int i=pos[x];
        e[i].w--;
        e[i^1].w++;
        x=e[i^1].to;
    }
    ans1++;
    ans2+=dis[t];
    return;
}
void EK()
{
    while(spfa()) 
    updata();return;//以上日常费用流
}
int main()
{
    memset(l,-1,sizeof(l));
    a=read();b=read();
    n=read()+1;m=read()+1;
    s=0;t=n*m+1;
    for(register int i=1;i<=n;i++)
     for(register int j=1;j<m;j++)//向右边的连边
    {
    	x=read();
    	add(id(i,j),id(i,j+1),1,-x);
    	add(id(i,j),id(i,j+1),1e9,0);
	}
	for(register int j=1;j<=m;j++)
	 for(register int i=1;i<n;i++)//向下边的连边
	{
		x=read();
		add(id(i,j),id(i+1,j),1,-x);
		add(id(i,j),id(i+1,j),1e9,0);
	}
	for(register int i=1;i<=a;i++)//与源点连边
	{
		k=read();x=read()+1;y=read()+1;
		add(s,id(x,y),k,0);
	}
	for(register int i=1;i<=b;i++)//与汇点连边
	{
		k=read();x=read()+1;y=read()+1;
		add(id(x,y),t,k,0);
	}
	EK();
	printf("%d",-ans2);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88069485
今日推荐