深海机器人问题

这里写图片描述
这题的题面描述。。有点问题。。坐标写的很乱。
这道题其实和著名DP问题方格取数很像qwq
我们发现机器人可以重复经过边,但只能对答案贡献一次,所以两点间连两条边。一条是容量1带的费用。
另一条没费用容量INF。用拆点吗?不用的。因为这个权值是走过边会有,所以这题中不用拆点。

起点连S容量机器人,终点连T容量机器人。注意算好点的坐标别发生计算错误调半天这样的傻事qwq。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e5+5;
const int INF=1e9+7;

struct edge{
    int u,to,next,w,c;
}e[MAXN<<1];


int head[MAXN],cnt=1;
inline void add(int u,int v,int w,int cost){
    e[++cnt]=(edge){u,v,head[u],w,cost},head[u]=cnt;
    e[++cnt]=(edge){v,u,head[v],0,-cost},head[v]=cnt;
}

int p,q,a,b,s,t;

bool vis[MAXN];
int dis[MAXN],pre[MAXN];
queue<int>qq;
bool SPFA(int x){
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    for(int i=s;i<=t;i++)dis[i]=-INF;
    qq.push(x);vis[x]=1;dis[x]=0;
    while(qq.size()){
        int u=qq.front();qq.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to,w=e[i].c;
            if(e[i].w){
                if(dis[u]+w>dis[v]){
                    dis[v]=dis[u]+w;pre[v]=i;
                    if(!vis[v]){
                        qq.push(v);
                        vis[v]=1;
                    }
                }
            }
        }
    }
    if(dis[t]==-INF)return 0;
    return 1;
} 

int MC(){
    int ans=0;
    while(SPFA(s)){
        int tem=INF;
        for(int i=pre[t];i;i=pre[e[i].u]){
            tem=min(tem,e[i].w);
        }
        for(int i=pre[t];i;i=pre[e[i].u]){
            e[i].w-=tem;e[i^1].w+=tem;
            ans+=tem*e[i].c;
        }
    }
    return ans;
}

int main(){
    int tem;
    scanf("%d%d%d%d",&a,&b,&p,&q);
    p++;q++;
    s=0,t=p*q+1;//(x,y)按照 y进制 一个y是一行x 
    for(int i=0;i<p;i++){//坐标为(j,i)
        for(int j=0;j<q-1;j++){
            int now=i*q+j+1;
            scanf("%d",&tem);
            add(now,now+1,1,tem);
            add(now,now+1,INF,0);
        } 
    }
    for(int i=0;i<q;i++){//坐标为(i,j)
        for(int j=0;j<p-1;j++){
            int now=j*q+i+1;
            scanf("%d",&tem);
            add(now,now+q,1,tem);
            add(now,now+q,INF,0);
        }
    }
    for(int i=1;i<=a;i++){
        int k,x,y;
        scanf("%d%d%d",&k,&y,&x);
        int now=y*q+x+1;
    //  cout<<now<<"ok"<<endl;
        add(s,now,k,0);
    }
    for(int i=1;i<=b;i++){//横行q个点,纵列p个点 
        int k,x,y;
        scanf("%d%d%d",&k,&y,&x);
        int now=y*q+x+1;
    //  cout<<"p:"<<p<<endl;
    //  cout<<"q:"<<q<<endl;
    //          cout<<now<<"ok"<<endl;
        add(now,t,k,0);
    }
    printf("%d\n",MC());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值