版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88069485
在一个 的矩阵中,每个点都有自己的权值
有 个起点, 个终点
每个起点都有 个机器人,每个终点可以到达 个机器人
机器人只能向右或向上走,当机器人经过某个点时可以取走当前点的权值(只能取一次
)
求到达终点的机器人的最大权值总和
数据范围:
鸣谢 大佬的讲解,算是比较能弄懂这题的建图了,一眼就看出正解的他太强啦%%%
根据数据范围和标签可以看出这题是一道网络流
容易看出这道题的模型有点类似于传纸条,因为格子的值是非负的,所以我显然越多机器人到达时越好的,这就是一个最大流。
现在我们要在此基础上使得权值总和最大,也就是一个最大费用最大流了
现在我们考虑费用
启动机器人是无代价的,日常费用0
主要考虑取走这个问题,由于每个只能取一次,所以容量为1,代价为其价值,但是如果单纯这样建是错误的,因为它取走之后还可以继续走,所以还要建一条“经过点”,容量为无穷大(无限经过),代价为0(经过当然没有代价了啦)
其它的日常网络流啦
依照网络流的套路,我们把费用取负,然后跑最小费用最大流即可
如图(真的良心绘图):绘图网址
#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);
}