传送门
深海机器人
题意:给定带一次性边权网格与若干机器人的起终点,规定起终点必须被机器人经过的次数,求所有机器人能够得到的最大边权和.
I think
最大费用流,源点向起点连边,终点向汇点连边,方格上的点向相邻点连流量为1费用为val的边.除此之外,对于题目要求,”多个机器人可以在同一时间占据同一位置“,方格上的点还要向相邻点连流量为Inf,费用为0的边.
注意题面所给最后所给起点与终点的坐标横纵是相反的对于方格中的点的编号,可用mp[][]数组+P*Q循环进行预处理.
Code
#include<cstdio>
#include<queue>
using namespace std;
const int sm = 260;
const int sn = 3080;
const int Inf = 0x3f3f3f3f;
int P,Q,tot=1,S,T;
int to[sn],hd[sm],nxt[sn],c[sn],f[sn];
int pre[sm],vis[sm],cst[sm],mp[17][17];
int Min(int x,int y) { return x<y?x:y; }
void Add(int u,int v,int x,int y) {
to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=x,f[tot]=y;
to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0,f[tot]=-y;
}
int Point(int x,int y) { return (Q+1)*y+x+1; }
void SPFA() {
int Ans=0,df,t;
queue<int>q;
while(true) {
for(int i=0;i<=T;++i) cst[i]=-Inf;
q.push(S),cst[S]=0;
while(!q.empty()) {
t=q.front(),q.pop(),vis[t]=0;
for(int i=hd[t];i;i=nxt[i])
if(c[i]>0&&cst[to[i]]<cst[t]+f[i]) {
cst[to[i]]=cst[t]+f[i];
pre[to[i]]=i;
if(!vis[to[i]]) {
vis[to[i]]=1;
q.push(to[i]);
}
}
}
if(cst[T]==-Inf) break;
df=Inf;
for(int i=T;i!=S;i=to[pre[i]^1])
df=Min(df,c[pre[i]]);
for(int i=T;i!=S;i=to[pre[i]^1])
c[pre[i]]-=df,c[pre[i]^1]+=df;
Ans+=df*cst[T];
}
printf("%d\n",Ans);
}
int main() {
int a,b,u,v,k,cnt=0;
scanf("%d%d%d%d",&a,&b,&P,&Q);
S=(P+1)*(Q+1)+1,T=S+1;
for(int i=0;i<=P;++i)
for(int j=0;j<=Q;++j)
mp[j][i]=++cnt;
for(int i=0;i<=P;++i)
for(int j=0;j<Q;++j) {
scanf("%d",&u);
Add(mp[j][i],mp[j+1][i],1,u);
Add(mp[j][i],mp[j+1][i],Inf,0);
}
for(int i=0;i<=Q;++i)
for(int j=0;j<P;++j) {
scanf("%d",&u);
Add(mp[i][j],mp[i][j+1],1,u);
Add(mp[i][j],mp[i][j+1],Inf,0);
}
for(int i=1;i<=a;++i)
scanf("%d%d%d",&k,&u,&v),Add(S,mp[v][u],k,0);
for(int i=1;i<=b;++i)
scanf("%d%d%d",&k,&u,&v),Add(mp[v][u],T,k,0);
SPFA();
return 0;
}