题目描述

火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车。登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动。探测车在移动中还必须采集岩石标本。每一块岩石标本由最先遇到它的探测车完成采集。每块岩石标本只能被采集一次。岩石标本被采集后,其他探测车可以从原来岩石标本所在处通过。探测车不能通过有障碍的地面。本题限定探测车只能从登陆处沿着向南或向东的方向朝传送器移动,而且多个探测车可以在同一时间占据同一位置。如果某个探测车在到达传送器以前不能继续前进,则该车所采集的岩石标本将全部损失。

用一个 P·Q 网格表示登陆舱与传送器之间的位置。登陆舱的位置在(X1,Y1)处,传送器

的位置在(XP ,YQ)处。

X 1,Y 1 X 2 , Y 1 X 3 , Y 1 ... X P-1, Y 1 X P , Y 1

X 1,Y 2 X 2 , Y 2 X 3 , Y 2 ... X P-1, Y 2 X P , Y 2

X 1, Y 3 X 2 , Y 3 X 3 ,Y 3 ... X P-1, Y 3 X P , Y 3

... ...

X 1 ,Y Q-1 X 2 , Y Q-1 X 3 , Y Q-1 ... X P-1, Y Q-1 X P , Y Q-1

X 1,Y Q X 2 , Y Q X 3 , Y Q ... X P-1, Y Q X P ,Y Q

给定每个位置的状态,计算探测车的最优移动方案,使到达传送器的探测车的数量最多,

而且探测车采集到的岩石标本的数量最多

输入输出格式

输入格式:

第 1行为探测车数,第 2 行为 P 的值,第3 行为Q 的值。接下来的 Q 行是表示登陆舱与传送器之间的位置状态的 P·Q 网格。用 3 个数字表示火星表面位置的状态:0 表示平坦无障碍,1表示障碍,2 表示石块。

输出格式:

每行包含探测车号和一个移动方向,0 表示向南移动,1 表示向东移动。

输入输出样例

输入样例#1: 复制

2
10
8
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0
0 0 0 1 0 2 0 0 0 0
1 1 0 1 2 0 0 0 0 1
0 1 0 0 2 0 1 1 0 0
0 1 0 1 0 0 1 1 0 0
0 1 2 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0

输出样例#1: 复制

1 1
1 1
1 1
1 1
1 0
1 0
1 1
1 1
1 1
1 1
1 0
1 0
1 1
1 0
1 0
1 0
2 1
2 1
2 1
2 1
2 0
2 0
2 0
2 0
2 1
2 0
2 0
2 1
2 0
2 1
2 1
2 1

说明

车数,P,Q<=35

这个题目和深海机器人很像,思路差不多,就是完全按照这个坐标轴建图就可以了。

不过有几个地方要注意的,一个就是建图需要用拆点,因为这个题目给的是点权,而深海机器人给的是边权,

如果一个题目经过一个点的次数有限制,那么就需要进行拆点,如果题目给的是边权就不需要,这个是为什么呢?

这个你可以看一下下面这个牛吃草问题,应该可以理解。

除了这个还有就是路径的输出,你需要理解一下,很容易就可以发现,这个路径数就是最大流,

还有就是每一个点有没有被经过,就只要看它的流量是不是>0,如果大于0,就是被经过了,否则就是没有被经过。

这个路径的输出其实很好理解。

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5;
struct edge
{int u, v, c, f, cost;edge(int u, int v, int c, int f, int cost) :u(u), v(v), c(c), f(f), cost(cost) {}
};
vector<edge>e;
vector<int>G[maxn];
int a[maxn];//找增广路每个点的水流量
int p[maxn];//每次找增广路反向记录路径
int d[maxn];//SPFA算法的最短路
int inq[maxn];//SPFA算法是否在队列中
int s, t;
void init()
{for (int i = 0; i <=maxn; i++)G[i].clear();e.clear();
}
void add(int u, int v, int c, int cost)
{e.push_back(edge(u, v, c, 0, cost));e.push_back(edge(v, u, 0, 0, -cost));int m = e.size();G[u].push_back(m - 2);G[v].push_back(m - 1);
}
bool bellman(int s, int t, int& flow, long long & cost)
{memset(d, inf, sizeof(d));memset(inq, 0, sizeof(inq));d[s] = 0; inq[s] = 1;//源点s的距离设为0,标记入队p[s] = 0; a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的)
queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
    q.push(s);while (!q.empty()){int u = q.front();q.pop();inq[u] = 0;//入队列标记删除for (int i = 0; i < G[u].size(); i++){edge & now = e[G[u][i]];int v = now.v;if (now.c > now.f && d[v] > d[u] + now.cost)//now.c > now.f表示这条路还未流满(和最大流一样)//d[v] > d[u] + e.cost Bellman 算法中边的松弛
            {// printf("d[%d]=%d d[%d]=%d %d d[%d]=%d\n", v,d[v],u, d[u], now.cost,v,d[u]+now.cost);// printf("\n");//printf("%d %d %d %d %d %d\n", u, now.u, now.v, now.c, now.f, now.cost);//printf("\n");d[v] = d[u] + now.cost;//Bellman 算法边的松弛p[v] = G[u][i];//反向记录边的编号a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量if (!inq[v]) { q.push(v); inq[v] = 1; }//Bellman 算法入队
            }}}if (d[t] == inf)return false;//找不到增广路flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flowcost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用//printf("%d %d\n", d[t], a[t]);for (int u = t; u != s; u = e[p[u]].u)//逆向存边
    {e[p[u]].f += a[t];//正向边加上流量e[p[u] ^ 1].f -= a[t];//反向边减去流量 (和增广路算法一样)//printf("e[%d]=%d e[%d]=%d\n", p[u], e[p[u]].f, p[u] ^ 1, e[p[u] ^ 1].f);
    }return true;
}
int MaxcostMaxflow(int s, int t, long long & cost)
{cost = 0;int flow = 0;while (bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和costreturn flow;//返回最大流,cost引用可以直接返回最小费用
}
int mp[110][110];
int mpp[110][110];
int n, m;
void dfs(int x,int y,int u,int k)
{for(int i=0;i<G[u].size();i++){int kx, ky, mov;edge &now = e[G[u][i]];if (now.v == s ||  now.v == u - n * m) continue;if (now.v == t) continue;if (now.f == 0) continue;now.f--;if(now.v>n*m){dfs(x, y, now.v, k);return;}if(mpp[x][y]+1==now.v){kx = x;ky = y + 1;mov = 1;}else{mov = 0;ky = y;kx = x + 1;}printf("%d %d\n", k, mov);dfs(kx, ky, now.v+n*m, k);return;}
}int main()
{int id = 1, k;cin >> k >> m >> n;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin >> mp[i][j];mpp[i][j] = id++;}}int s = 0, t = 2 * n * m + 1;if (mp[1][1] != 1) add(s, mpp[1][1], k, 0);if (mp[n][m] != 1) add(mpp[n][m] + n * m, t, k, 0);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if (mp[i][j] == 1) continue;add(mpp[i][j], mpp[i][j] + n * m, inf, 0);if (mp[i][j] == 2){add(mpp[i][j], mpp[i][j] + n * m, 1, -1);}if(i!=1&&mp[i-1][j]!=1){add(mpp[i - 1][j] + n * m, mpp[i][j], inf, 0);}if(j!=1&&mp[i][j-1]!=1){add(mpp[i][j - 1] + n * m, mpp[i][j], inf, 0);}}}ll cost = 0;int ans = MaxcostMaxflow(s, t, cost);for(int i=1;i<=ans;i++){dfs(1, 1, 1, i);}return 0;
}

转载于:https://www.cnblogs.com/EchoZQN/p/10797861.html

火星探险问题 网络流相关推荐

  1. P3356 火星探险问题(网络流)

    P3356 火星探险问题 对于一个第一次经过会有价值,但是之后经过没有价值的点,我们的处理方法就是只连一条流量为1并且有费用的边,再连接流量为INF但是没有费用的边,这样我们要使得价值最大就会优先流有 ...

  2. 网络流二十四题之二十二 —— 火星探险问题

    火星探险问题 Description 火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车. 登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动. 探测车在移动中还必须采集岩石标本. ...

  3. 【Luogu】P3356火星探险问题(费用流)

    题目链接 网络流一条边都不能多连?没道理呀? 不过单看这题的确是个sb题-- #include<cstdio> #include<algorithm> #include< ...

  4. 洛谷 - P3356 火星探险问题(最大费用最大流+拆点+路径打印)

    题目链接:点击查看 题目大意:给出一个n*m的矩阵,每个点都有一个数字: 0:平坦无障碍 1:障碍 2:石块 现在在点(1,1)处有k个探测车,他们都要去往点(n,m)处,探测车只能向下或向右行驶,现 ...

  5. 解题报告:线性规划与网络流24题

    目录 A.飞行员配对方案问题 (二分图最大匹配)(最大流)[提高+/省选- ] B.太空飞行计划问题(最大权闭合图转最小割.最小割方案输出)[省选/NOI- ] C.最小路径覆盖问题(有向无环图最小路 ...

  6. 网络流 24 题汇总(LOJ 上只有 22 题???)

    太裸的我就不放代码了...(黑体字序号的题表示值得注意) 1.搭配飞行员 [LOJ#6000] 二分图最大匹配. 2.太空飞行计划 [LOJ#6001] 最小割常规套路.输出方案.(注:这题换行符要用 ...

  7. [刷题记录] luogu网络流24题 及 网络流心得体会 及 经典模型不定期更新

    文章目录 信息汇总表格 飞行员配对方案问题 分配问题 运输问题 数字梯形问题 最小路径覆盖问题 魔术球问题 圆桌问题 试题库问题 深海机器人问题 航空路线问题 火星探险问题 太空飞行计划问题 方格取数 ...

  8. 「网络流24题」 题目列表

    「网络流24题」 题目列表 序号 题目标题 模型 题解 1 飞行员配对方案问题 二分图最大匹配 <1> 2 太空飞行计划问题 最大权闭合子图 <2> 3 最小路径覆盖问题 二分 ...

  9. 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)

    ------------------------------------------------------------------------------------ 17/24 --------- ...

  10. 图论专题1(网络流)

    推荐阅读: 网络流基础知识和Dinic:http://www.cnblogs.com/SYCstudio/p/7260613.html#3848907 建模:https://www.cnblogs.c ...

最新文章

  1. MATLAB表白利器
  2. java系统排序_Java实现二进制排序树
  3. 论文阅读:Multi-Scale Triplet CNN for Person Re-Identification
  4. No such file or class on classpath: WordCount
  5. 【ArcGIS遇上Python】ArcGIS批量为多个矢量图层添加一个或多个字段(Add Field)案例实现
  6. 知乎阅读三百万的生信学习指南
  7. 暑期训练日志----2018.7.30
  8. svpwm仿真_【好物推荐】《现代永磁同步电机控制原理及MATLAB仿真》
  9. Windows 8实例教程系列 - 开篇
  10. 自己配置外接屏幕和驱动,最终通过hdmi连接
  11. 多线程3,线程池封装库
  12. OSEK直接网络管理(NM)
  13. 年会抽奖程序,开箱即用
  14. 实践致知第6享:QQ截图的文字识别功能
  15. 3.4 Go语言从入门到精通:包管理工具之Go module
  16. 解决​excel里一复制就卡死的经验分享【转】
  17. Java随笔-线程stop与interrupt
  18. 2020 用html jQuery实现广告轮播图自动切换 滚动页面 鼠标悬浮下标且左右切换图片
  19. Android开发人才前景分析及建议
  20. centos 安装Times New Roman

热门文章

  1. outlook安全电子邮件实现
  2. Windows窗体之ShowWindow函数分析
  3. I8700手机使用感受
  4. ftp服务器文件不显示,ftp服务器不显示文件夹大小
  5. 速率bps(kbps、Mbps)和每秒字节传输B/s(KB/s、MB/s)的关系如下
  6. 胶片效果滤镜渲染工具:DxO FilmPack Mac
  7. 哪种云计算机能玩游戏,低配置电脑的福音,体验腾讯START云游戏:只要有网就能玩这几个游戏,除了Mac版还有Win版!...
  8. 【String类】StringBuffer类 StringBuilder类
  9. 实时视频带宽的计算过程
  10. 自定义 QGraphicsItem