洛谷 P4012 深海机器人问题【费用流】

题目链接:https://www.luogu.org/problemnew/show/P4012

洛谷 P4012 深海机器人问题

输入输出样例

输入样例#1:

1 1
2 2
1 2
3 4
5 6
7 2
8 10
9 3
2 0 0
2 2 2

输出样例#1:

42

说明

题解:建图方法如下:

  对于矩阵中的每个点,向东、向北分别与其相邻点都要连两条边(重边):

    1)容量为1,费用为该边价值的边;

    2)容量为INF,费用为0的边(因为多个深海机器人可以在同一时间占据同一位置)。

  对于每个起点:从S(源点)到这个点连:容量为该点机器人数,费用为0的边。

  对于每个终点:从这个点到T(汇点)连:容量为该点机器人数,费用为0的边。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N = 455;
  5 const int M = N*4+30;
  6 const int INF = 0x3f3f3f3f;
  7 struct Edge { int to,next,cap,flow,cost; }edge[M];
  8 int head[N],tol;
  9 int pre[N],dis[N];
 10 bool vis[N];
 11 int V;
 12 void init(int n) {
 13     V = n;
 14     tol = 0;
 15     memset(head,-1,sizeof(head));
 16 }
 17 void addedge(int u,int v,int cap,int cost) {
 18     edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++;
 19     edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++;
 20 }
 21 bool spfa(int s,int t) {
 22     queue<int>q;
 23     for(int i = 0;i < V;i++) {
 24         dis[i] = INF;
 25         vis[i] = false;
 26         pre[i] = -1;
 27     }
 28     dis[s] = 0;
 29     vis[s] = true;
 30     q.push(s);
 31     while(!q.empty()) {
 32         int u = q.front();
 33         q.pop();
 34         vis[u] = false;
 35         for(int i = head[u]; i != -1;i = edge[i].next) {
 36             int v = edge[i].to;
 37             if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) {
 38                 dis[v] = dis[u] + edge[i].cost;
 39                 pre[v] = i;
 40                 if(!vis[v]) {
 41                     vis[v] = true;
 42                     q.push(v);
 43                 }
 44             }
 45         }
 46     }
 47     if(pre[t] == -1) return false;
 48     else return true;
 49 }
 50 int minCostMaxflow(int s,int t,int &cost) {
 51     int flow = 0;
 52     cost = 0;
 53     while(spfa(s,t)) {
 54         int Min = INF;
 55         for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) {
 56             if(Min > edge[i].cap - edge[i].flow)
 57                 Min = edge[i].cap - edge[i].flow;
 58         }
 59         for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) {
 60             edge[i].flow += Min;
 61             edge[i^1].flow -= Min;
 62             cost += edge[i].cost * Min;
 63         }
 64         flow += Min;
 65     }
 66     return flow;
 67 }
 68 int main() {
 69     int a, b, p, q, k, x, y, i, j, ans = 0;
 70     scanf("%d%d", &a, &b);//出发和目的地数目
 71     scanf("%d%d", &p, &q);
 72     init((p+1)*(q+1)+3);
 73
 74     int s = (p+1)*(q+1)+1, t = (p+1)*(q+1)+2;
 75
 76     for(i = 0; i <= p; ++i) {//p+1行,向东移动
 77         for(j = 0; j < q; ++j) {
 78             scanf("%d", &x);//边上的标本价值
 79             addedge(i*(q+1)+j, i*(q+1)+j+1, 1, -x);
 80             addedge(i*(q+1)+j, i*(q+1)+j+1, INF, 0);
 81         }
 82     }
 83     for(j = 0; j <= q; ++j) {//q+1列,向北移动
 84         for(i = 0; i < p; ++i) {
 85             scanf("%d", &x);
 86             addedge(i*(q+1)+j, i*(q+1)+j+q+1, 1, -x);
 87             addedge(i*(q+1)+j, i*(q+1)+j+q+1, INF, 0);
 88         }
 89     }
 90     for(i = 1; i <= a; ++i) {//起点
 91         scanf("%d%d%d", &k, &x, &y);
 92         addedge(s, x*(q+1)+y, k, 0);
 93     }
 94     for(i = 1; i <= b; ++i) {//终点
 95         scanf("%d%d%d", &k, &x, &y);
 96         addedge(x*(q+1)+y, t, k, 0);
 97     }
 98     minCostMaxflow(s, t, ans);
 99     printf("%d\n", -ans);
100     return 0;
101 }

原文地址:https://www.cnblogs.com/GraceSkyer/p/9038586.html

时间: 2024-10-09 22:03:17

洛谷 P4012 深海机器人问题【费用流】的相关文章

洛谷 1004 dp或最大费用流

思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l],dp[i][j-1][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k][l-1])+map[i][j]+map[k][l]; 若两点相同减去一个map[i][j]即可 费用流方法(可以扩展为k条路径,但时间复杂度较高): 源点连接左上角点流量为k.费用为0,右下角

洛谷OJ P1126 机器人搬重物 解题报告

洛谷OJ P1126 机器人搬重物 解题报告 by MedalPluS [题目描述]    机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格,有些格子为不可移动的障碍.机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方.机器人接受的指令有:向前移动1步(Creep):向前移动2步(Walk):向前移动3步(Run):向左转(Left):向右转(Right).

洛谷 P4014 分配问题 【最小费用最大流+最大费用最大流】

其实KM更快--但是这道题不卡,所以用了简单粗暴的费用流,建图非常简单,s向所有人连流量为1费用为0的边来限制流量,所有工作向t连流量为1费用为0的边,然后对应的人和工作连(i,j,1,cij),跑一遍最小费用最大流再跑一遍最大费用最大流即可.方便起见直接重建图了. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const

P4012 深海机器人问题

\(\color{#0066ff}{题目描述}\) 深海资源考察探险队的潜艇将到达深海的海底进行科学考察. 潜艇内有多个深海机器人.潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动. 深海机器人在移动中还必须沿途采集海底生物标本.沿途生物标本由最先遇到它的深海机器人完成采集. 每条预定路径上的生物标本的价值是已知的,而且生物标本只能被采集一次. 本题限定深海机器人只能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一位置. 用一个 \(P\times Q\) 网

luogu P4012 深海机器人问题

费用流问题,每个样本选一次,就连一条capacity为1,权为给定的值,因为可以重复走,再连capacity为无穷,权为0的边,再一次连接给定的出点和汇点即可 #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&(-x)) typedef long long LL; const int maxm = 3e3+5; const int INF = 0x3f3f3f3f; struct edge{ int

洛谷 P4015 运输问题 【最小费用最大流+最大费用最大流】

s向仓库i连ins(s,i,a[i],0),商店向t连ins(i+m,t,b[i],0),商店和仓库之间连ins(i,j+m,inf,c[i][j]).建两次图分别跑最小费用最大流和最大费用最大流即可. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1000005,inf=1e9; int n,m,h

洛谷 P3254 圆桌问题【最大流】

s向所有单位连流量为人数的边,所有饭桌向t连流量为饭桌容量的边,每个单位向每个饭桌连容量为1的边表示这个饭桌只能坐这个单位的一个人.跑dinic如果小于总人数则无解,否则对于每个单位for与它相连.满流.另一端不是s的点则是最终方案 #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1000005,inf

洛谷P4003 无限之环(infinityloop)(网络流,费用流)

洛谷题目传送门 题目 题目描述 曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏: 游戏在一个 n ? m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在格子某些方向的边界的中点有接口,所有水管的粗细都相同,所以如果两个相邻方格的共边界的中点都有接头,那么可以看作这两个接头互相连接.水管有以下 15 种形状: 游戏开始时,棋盘中水管可能存在漏水的地方. 形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的地方. 玩家可以进行一种操作:

洛谷P3381——费用流模板题

嗯..随便刷了一道费用流的模板题....来练练手. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int h[5210],d[5210],used[5210],que[100010],last[5210]; int k=1,INF=0x7fffffff,ans1=0,ans2=0; inline int read(){ int t=1,num=0; char c=ge