【网络流24题】深海机器人(最大费用流)

传送门

    深海机器人
    题意:给定带一次性边权网格与若干机器人的起终点,规定起终点必须被机器人经过的次数,求所有机器人能够得到的最大边权和.

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值