火星探险问题 网络流
题目描述
火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车。登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动。探测车在移动中还必须采集岩石标本。每一块岩石标本由最先遇到它的探测车完成采集。每块岩石标本只能被采集一次。岩石标本被采集后,其他探测车可以从原来岩石标本所在处通过。探测车不能通过有障碍的地面。本题限定探测车只能从登陆处沿着向南或向东的方向朝传送器移动,而且多个探测车可以在同一时间占据同一位置。如果某个探测车在到达传送器以前不能继续前进,则该车所采集的岩石标本将全部损失。
用一个 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 表示向东移动。
输入输出样例
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 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
火星探险问题 网络流相关推荐
- P3356 火星探险问题(网络流)
P3356 火星探险问题 对于一个第一次经过会有价值,但是之后经过没有价值的点,我们的处理方法就是只连一条流量为1并且有费用的边,再连接流量为INF但是没有费用的边,这样我们要使得价值最大就会优先流有 ...
- 网络流二十四题之二十二 —— 火星探险问题
火星探险问题 Description 火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车. 登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动. 探测车在移动中还必须采集岩石标本. ...
- 【Luogu】P3356火星探险问题(费用流)
题目链接 网络流一条边都不能多连?没道理呀? 不过单看这题的确是个sb题-- #include<cstdio> #include<algorithm> #include< ...
- 洛谷 - P3356 火星探险问题(最大费用最大流+拆点+路径打印)
题目链接:点击查看 题目大意:给出一个n*m的矩阵,每个点都有一个数字: 0:平坦无障碍 1:障碍 2:石块 现在在点(1,1)处有k个探测车,他们都要去往点(n,m)处,探测车只能向下或向右行驶,现 ...
- 解题报告:线性规划与网络流24题
目录 A.飞行员配对方案问题 (二分图最大匹配)(最大流)[提高+/省选- ] B.太空飞行计划问题(最大权闭合图转最小割.最小割方案输出)[省选/NOI- ] C.最小路径覆盖问题(有向无环图最小路 ...
- 网络流 24 题汇总(LOJ 上只有 22 题???)
太裸的我就不放代码了...(黑体字序号的题表示值得注意) 1.搭配飞行员 [LOJ#6000] 二分图最大匹配. 2.太空飞行计划 [LOJ#6001] 最小割常规套路.输出方案.(注:这题换行符要用 ...
- [刷题记录] luogu网络流24题 及 网络流心得体会 及 经典模型不定期更新
文章目录 信息汇总表格 飞行员配对方案问题 分配问题 运输问题 数字梯形问题 最小路径覆盖问题 魔术球问题 圆桌问题 试题库问题 深海机器人问题 航空路线问题 火星探险问题 太空飞行计划问题 方格取数 ...
- 「网络流24题」 题目列表
「网络流24题」 题目列表 序号 题目标题 模型 题解 1 飞行员配对方案问题 二分图最大匹配 <1> 2 太空飞行计划问题 最大权闭合子图 <2> 3 最小路径覆盖问题 二分 ...
- 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)
------------------------------------------------------------------------------------ 17/24 --------- ...
- 图论专题1(网络流)
推荐阅读: 网络流基础知识和Dinic:http://www.cnblogs.com/SYCstudio/p/7260613.html#3848907 建模:https://www.cnblogs.c ...
最新文章
- MATLAB表白利器
- java系统排序_Java实现二进制排序树
- 论文阅读:Multi-Scale Triplet CNN for Person Re-Identification
- No such file or class on classpath: WordCount
- 【ArcGIS遇上Python】ArcGIS批量为多个矢量图层添加一个或多个字段(Add Field)案例实现
- 知乎阅读三百万的生信学习指南
- 暑期训练日志----2018.7.30
- svpwm仿真_【好物推荐】《现代永磁同步电机控制原理及MATLAB仿真》
- Windows 8实例教程系列 - 开篇
- 自己配置外接屏幕和驱动,最终通过hdmi连接
- 多线程3,线程池封装库
- OSEK直接网络管理(NM)
- 年会抽奖程序,开箱即用
- 实践致知第6享:QQ截图的文字识别功能
- 3.4 Go语言从入门到精通:包管理工具之Go module
- 解决​excel里一复制就卡死的经验分享【转】
- Java随笔-线程stop与interrupt
- 2020 用html jQuery实现广告轮播图自动切换 滚动页面 鼠标悬浮下标且左右切换图片
- Android开发人才前景分析及建议
- centos 安装Times New Roman
热门文章
- outlook安全电子邮件实现
- Windows窗体之ShowWindow函数分析
- I8700手机使用感受
- ftp服务器文件不显示,ftp服务器不显示文件夹大小
- 速率bps(kbps、Mbps)和每秒字节传输B/s(KB/s、MB/s)的关系如下
- 胶片效果滤镜渲染工具:DxO FilmPack Mac
- 哪种云计算机能玩游戏,低配置电脑的福音,体验腾讯START云游戏:只要有网就能玩这几个游戏,除了Mac版还有Win版!...
- 【String类】StringBuffer类 StringBuilder类
- 实时视频带宽的计算过程
- 自定义 QGraphicsItem