1018 Public Bike Management (30分) 思路分析 + 满分代码
题目
There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.
The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.
When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.
The above figure illustrates an example. The stations are represented by vertices and the roads correspond to the edges. The number on an edge is the time taken to reach one end station from another. The number written inside a vertex S is the current number of bikes stored at S. Given that the maximum capacity of each station is 10. To solve the problem at S3 , we have 2 different shortest paths:
PBMC -> S1 -> S3 . In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1 and then take 5 bikes to S3 , so that both stations will be in perfect conditions.PBMC -> S2 -> S3 . This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 numbers: Cmax (≤100), always an even number, is the maximum capacity of each station; N (≤500), the total number of stations; Sp , the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads. The second line contains N non-negative numbers C
i (i=1,⋯,N) where each Ci is the current number of bikes at Si respectively. Then M lines follow, each contains 3 numbers: Si , Sj , and Tij which describe the time Tij taken to move betwen stations Si and Sj . All the numbers in a line are separated by a space.
Output Specification:
For each test case, print your results in one line. First output the number of bikes that PBMC must send. Then after one space, output the path in the format: 0−>S
1 −>⋯−>Sp . Finally after another space, output the number of bikes that we must take back to PBMC after the condition of Sp is adjusted to perfect.
Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge's data guarantee that such a path is unique.
Sample Input:
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
Sample Output:
3 0->2->3 0
中文翻译
杭州市设有公共自行车服务,为来自世界各地的游客提供了极大的便利。可以在任何车站租用一辆自行车,然后将其还给城市中的其他车站。
公共自行车管理中心(PBMC)不断监视所有站点的实时容量。如果工作站刚满一半,则称其处于理想状态。如果一个车站已满或空了,PBMC会收集或派送自行车以将该车站的状况调整到最佳状态。而且,途中的所有车站也会调整到完美状态。
当报告问题站点时,PBMC将始终选择到达该站点的最短路径。如果最短路径多于一条,则将选择需要从PBMC发送的自行车数量最少的那条路径。
思路分析
- 首先,遇到最短路径,肯定是
Dijstra
,但题目说了,可能会有多条最短路径,我们要找到全部路径怎么办?把每一个路径都保存下来吗?可以,但没必要。我们只需要记录最短路径上每个节点的直接前驱就可以了,而这个,在Dijstra算法中,只需要在更新过程中(d[v] = d[u] + e[u][v]
)加上一条语句就可以了(prev[v].push_back(u)
),非常简单。如果它有多个最短路径,那么它就有多个直接前驱,因此,每个节点都应该有一个vector来保存它的全部最短路径的直接前驱,最终,就是需要一个vector数组。 - 找到最短路径显然是不够的,我们还要进行选择,选择PCBC按哪一条路走,需要带过去的自行车最少。所以,我们要遍历全部最短路径,于是
dfs
就出场了,因为我们保存的是它的直接前驱,所以需要从sp往PCBC去遍历。对于每一个最短路径,模拟一次PCBC需要进行的调整过程(逐个访问节点,并根据它的当前容量计算它达到完美需要的自行车参数),记录需要带过来或带回去的自行车数目,如果更少,则选择这条路径。 - 有一个好的技巧是,我们的完美状态是
cmax/2
,刚开始给出了所有站点的当前容量,但我们不直接保存它的当前容量,我们用diff数组保存每个站点当前容量与完美状态的差值,这样,我们很容易根据这个值的正负知道它是缺少自行车,缺少几个?或者是需要自行车,需要几个?当然,这不是我这个菜鸡能想出来的,还是参考了柳婼大神的代码之后改出来的,大神是真的强!!! - 所以,总的来说就是,Dijstra找到全部最短路径,dfs遍历每个最短路径并找到最好的那个,选择路径的原则就是,
距离最短>距离相同但发送的自行车最少>距离相同发送的自行车也相同但带回的自行车最少
。 - 这里有个问题就是,如果PCBC最终需要发送自行车,那么带回的自行车就是0,如果PCBC最终需要带回自行车,那么发送的自行车就是0,所以应该只需要一个参数就能搞定,我的代码是参照柳神的代码写的,我试着按这个想法去改了改代码,但是并不能通过,反而改出了bug,然后就放弃了,不知道是我的理解有问题,还是我没改对,如果有成功的小伙伴希望能戳一下我,谢谢啦!
满分代码
我的代码注释已经很详细了,应该都能看明白,我就不解释了,有问题可以在评论指出。
#include <iostream>
#include <algorithm>
#include <climits>
#include <vector>
using namespace std;
// 边距
int edge[501][501];
// 起点到每个点的最短距离
int dis[501];
// 起点到每个点的最短路径可能有多个,同一个点就会有多个前驱,我们用vector保存它的所有前驱(都是最短路径下的前驱)
vector<int> pre[501];
// 各个站点当前容量
// 有个窍门是我们这里不直接保存它的当前容量,而且保存它的完美容量的差,
// 这样我们就能很快知道这个站点 缺少 或者 多出 几辆自行车
int diff[501];
// PCBC需要带去,或带回的最少的自行车数
int min_take = ;
// 对应的那个路径
vector<int> path, temp_path;
// 深度优先遍历,从PCBC到S有一个或多个最短路径,比较每种情况下,PCBC最终带过去或带回去的自行车最少
// 要求沿途经过的所有站点都要调整到完美状态
// 因为我们保存的是前驱,所以我们从s往PCBC遍历,temp_list保存本次路径
void dfs(int sp) {
// 保存自己
temp_path.push_back(sp);
// 路径完整了
if (sp == 0) {
// 选择这个路径,PCBC最终需要带回去或带过来几辆自行车
int temp_take = 0;
// temp_list里面是倒着的(如:sp 3 2 1 0),所以我们要倒序遍历
for (int i = temp_path.size() - 1; i >= 0; --i) {
// 当前站点
int v = temp_path[i];
// 当前站点多出自行车
if (diff[v] > 0) {
temp_take -= diff[v];
} else {
// 当前站点完美或缺少自行车,-diff[i]就是缺的数量
if (temp_take >= -diff[v]) {
// 抵消掉一部分带回去的,达到完美状态
temp_take += diff[v]; // diff[i]本身就是负数
} else {
// 不够抵消,自己缺少 -diff[i],要带回去的只有temp_back个,
// PCBC还需要带来-diff[i] - temp_back个,temp_back就=0
temp_take += (-diff[v] - temp_take);
}
}
}
// 选择本条路径,PCBC需要带过来的自行车更少一些,选择本条路径
if (abs(min_take) > abs(temp_take)) {
path = temp_path;
min_take = temp_take;
}
// 移除自己,“前呼后应原则”
temp_path.pop_back();
return;
}
// 多个前驱
for (int i = 0; i < pre[sp].size(); ++i) {
// 选择其中一条
dfs(pre[sp][i]);
}
// 移除自己,“前呼后应原则”
temp_path.pop_back();
return;
}
int main() {
// 初始化边距
fill(edge[0], edge[0] + 501 * 501, INT_MAX);
// 初始化起点到其他点的最短距离
fill(dis, dis + 501, INT_MAX);
// c每个站点容量,n个城市,s待处理的站点,m是m条边的距离
// 编号从1开始,P编号0表示PCBC
int c, n, s, m;
scanf("%d %d %d %d", &c, &n, &s, &m);
// 各个站点当前容量
for (int i = 1; i <= n; ++i) {
scanf("%d", &diff[i]);
// 计算与完美状态的数量差
diff[i] = diff[i] - c / 2;
}
// m条边
int from, to, d;
while (m-- > 0) {
scanf("%d %d %d", &from, &to, &d);
edge[from][to] = edge[to][from] = d;
}
// Dijstraq求PCBC到每个点的最短距离,并记录前驱
bool visit[501] = {false};
// 初始化
dis[0] = 0;
// 最短路径
for (int i = 0; i <= n; ++i) {
int u = -1, min_dis = INT_MAX;
for (int j = 0; j <= n; ++j) {
if (!visit[j] && dis[j] < min_dis) {
u = j;
min_dis = dis[j];
}
}
if (u == -1)
break;
visit[u] = true;
for (int v = 0; v <= n; ++v) {
if (!visit[v] && edge[u][v] != INT_MAX) {
if (dis[u] + edge[u][v] < dis[v]) {
// 更新到v的最短路径
dis[v] = dis[u] + edge[u][v];
// 更新它的前驱
pre[v].clear();
pre[v].push_back(u);
} else if (dis[u] + edge[u][v] == dis[v]) {
// 多了一条最短路径就多了一个前驱
pre[v].push_back(u);
}
}
}
}
// 找到了PCBC到全部节点的最短路径,也找到了这些最短路径上每个节点的一个或多个直接前驱
// 关注的是从PCBC到s的多个最短路径中,需要从PCBC带过去或带回来的自行车最少的路径,使用dfs
dfs(s);
// path保存PCBC选择的最短路径,min_take需要带过来的自行车,min_back需要带回去的自行车
printf("%d 0", min_take > 0 ? min_take : 0);
// temp s 3 2 1 0,需要输出 0->1->2->3->s
for (int i = path.size() - 2; i >= 0; --i)
printf("->%d", path[i]);
printf(" %d", min_take > 0 ? 0 : -min_take);
return 0;
}
1018 Public Bike Management (30分) 思路分析 + 满分代码的更多相关文章
- PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)
1018 Public Bike Management (30 分) There is a public bike service in Hangzhou City which provides ...
- 1018 Public Bike Management (30 分)
There is a public bike service in Hangzhou City which provides great convenience to the tourists fro ...
- 1018 Public Bike Management (30分) PAT甲级真题 dijkstra + dfs
前言: 本题是我在浏览了柳神的代码后,记下的一次半转载式笔记,不经感叹柳神的强大orz,这里给出柳神的题解地址:https://blog.csdn.net/liuchuo/article/detail ...
- 1018 Public Bike Management (30分) (迪杰斯特拉+dfs)
思路就是dijkstra找出最短路,dfs比较每一个最短路. dijkstra可以找出每个点的前一个点, 所以dfs搜索比较的时候怎么处理携带和带走的数量就是关键,考虑到这个携带和带走和路径顺序有关, ...
- 【PAT甲级】1018 Public Bike Management (30 分)(SPFA,DFS)
题意: 输入四个正整数C,N,S,M(c<=100,n<=500),分别表示每个自行车站的最大容量,车站个数,此次行动的终点站以及接下来的M行输入即通路.接下来输入一行N个正整数表示每个自 ...
- 1018 Public Bike Management (30)(30 分)
时间限制400 ms 内存限制65536 kB 代码长度限制16000 B There is a public bike service in Hangzhou City which provides ...
- PAT Advanced 1018 Public Bike Management (30) [Dijkstra算法 + DFS]
题目 There is a public bike service in Hangzhou City which provides great convenience to the tourists ...
- 1018. Public Bike Management (30)
时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue There is a public bike service i ...
- 1025 PAT Ranking (25分) 思路分析 +满分代码
题目 Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of ...
随机推荐
- WinRAR代码执行漏洞复现
漏洞介绍 WinRAR 是一款流行的解压缩工具,据其官网上发布的数据,全球有超过5亿的用户在使用 2019年2月20日,安全厂商 checkpoint 发布了名为<Extracting a 19 ...
- [PHP][thinkphp5] 学习二:路由、配置调用、常量定义调用
路由: 其实TP5就是一个集多家框架所长而成的,感觉失去了自己的特色!路由这块呢类似于laravel框架!废话不说直接上码! 路由配置,类似laravel,就在route.php文件里配置路由(文件所 ...
- 感受python之美,python简单易懂的小例子
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 1 简洁之美 通过一行代码,体会Python语言简洁之美 2 Python ...
- hadoop 伪分布配置
配置 Hadoop 伪分布式 任务配置说明: VMware 15 Centos 6.5 java -jdk 1.8 hadoop-2.6.0-cdh5.14.0.tar.gz 第一步 自行安装虚拟机 ...
- python 给字典按值排序,同样适合于其他
sorted_items = sorted(dico.items(),key=lambda x:(-x[1],x[0]))
- springmvc配置数据源方式
1 阿里巴巴的druid数据源 <!-- 配置数据源 使用的是Druid数据源 -->-<bean destroy-method="close" init-met ...
- 解决Macbook Pro 2017安装Windows10双系统后在Windows系统中Apple蓝牙鼠标不能使用问题
MAC BOOK PRO 2017安装Windows10双系统 在Windows系统中蓝牙鼠标不能使用解决办法 最近因工作需要,macOS系统不能要求,大部分工作必须要在Windows系统中进行,最初 ...
- PHP把PNG图片转化为JPG时透明背景变黑色
$type = exif_imagetype($srcimg); switch($type) { case 1: $simg = imagecreatefromgif($srcimg); break; ...
- 必应每日图片api
https://cn.bing.com/HPImageArchive.aspx?format=xml&cc=jp&idx=0&n=1 format = 'xml' | 'j ...
- Ubuntu 18.04更换apt-get源
使用apt-get安装时,会很慢,更换了国内的源后,就可以解决这个问题了. 1. 备份sources.list文件 sudo cp /etc/apt/sources.list /etc/apt/sou ...