【网络流24题20】深海机器人问题
题面戳我
这里推荐一下相关的题目(我可以说是双倍经验题吗)
Luogu2045 方格取数加强版其实还是有点区别的啦
sol
这个题是说边上面有边权所以就不需要拆点了嗷。
每条边可以采集一次,那么肯定要连一条费用为收益容量为1的边。
那这条边就不可以走了吗?
显然不是。
所有还要连一条费用为0容量为\(inf\)的边。
所以就这样建边然后跑费用流就好啦。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf = 1e9;
const int N = 2000;
struct edge{int to,next,w,cost;}a[N<<5];
int A,B,p,q,s,t,pos[100][100],tot,head[N],cnt=1,dis[N],vis[N],pe[N],ans;
queue<int>Q;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
void link(int u,int v,int w,int cost)
{
a[++cnt]=(edge){v,head[u],w,cost};
head[u]=cnt;
a[++cnt]=(edge){u,head[v],0,-cost};
head[v]=cnt;
}
bool spfa()
{
memset(dis,63,sizeof(dis));
dis[s]=0;Q.push(s);
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int e=head[u];e;e=a[e].next)
{
int v=a[e].to;
if (a[e].w&&dis[v]>dis[u]+a[e].cost)
{
dis[v]=dis[u]+a[e].cost;pe[v]=e;
if (!vis[v]) vis[v]=1,Q.push(v);
}
}
vis[u]=0;
}
if (dis[t]==dis[0]) return false;
int sum=inf;
for (int i=t;i^s;i=a[pe[i]^1].to)
sum=min(sum,a[pe[i]].w);
ans-=sum*dis[t];
for (int i=t;i^s;i=a[pe[i]^1].to)
a[pe[i]].w-=sum,a[pe[i]^1].w+=sum;
return true;
}
int main()
{
A=gi();B=gi();p=gi();q=gi();
for (int i=0;i<=p;i++)
for (int j=0;j<=q;j++)
pos[i][j]=++tot;
s=tot+1;t=s+1;
for (int i=0;i<=p;i++)
for (int j=0;j<q;j++)
{
int val=gi();
link(pos[i][j],pos[i][j+1],1,-val);
link(pos[i][j],pos[i][j+1],inf,0);
}
for (int j=0;j<=q;j++)
for (int i=0;i<p;i++)
{
int val=gi();
link(pos[i][j],pos[i+1][j],1,-val);
link(pos[i][j],pos[i+1][j],inf,0);
}
while (A--)
{
int k=gi(),x=gi(),y=gi();
link(s,pos[x][y],k,0);
}
while (B--)
{
int r=gi(),x=gi(),y=gi();
link(pos[x][y],t,r,0);
}
while (spfa());
printf("%d\n",ans);
return 0;
}