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 ...
随机推荐
- C. Standard Free2play --div
https://codeforces.com/contest/1238/problem/C 题意:下台阶的时候只有一种方式,拉动当前台阶x的 level,然后当前的台阶关闭,调到下边的台阶x-1,如果 ...
- 功能测试--聊天功能测试&微信聊天
微信聊天功能测试 发送对象 普通用户.公众号.群.其他特殊主体 衍生功能 转发.语音转文字.删除等 消息发送 单聊.群聊.语音.文字.图片.表情.链接.字符及长度 消息管理 发布通知.接受通知.发文件 ...
- 深入分析Redis的主从复制机制
一.前言 最近由于疫情影响,时间比较多,所以开始学习之前一直想学,但是却没时间学的Redis.这两天研究了一下Redis的持久化以及主从复制机制,现在已经很晚了,就不多废话了.这篇博客就来谈一谈R ...
- Python爬虫篇(代理IP)--lizaza.cn
在做网络爬虫的过程中经常会遇到请求次数过多无法访问的现象,这种情况下就可以使用代理IP来解决.但是网上的代理IP要么收费,要么没有API接口.秉着能省则省的原则,自己创建一个代理IP库. 废话不多说, ...
- 非常简单的string驻留池,你对它真的了解吗
昨天看群里在讨论C#中的string驻留池,炒的火热,几轮下来理论一堆堆,但是在证据提供上都比较尴尬.虽然这东西很基础,但比较好的回答也不是那么容易,这篇我就以我能力范围之内跟大家分享一下 一:无处不 ...
- PHP Ajax 跨域问题解决方案
本文通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.0751.tv,而请求的域名是server.0751.tv. 如果直接使用ajax访问 ...
- 超详细步骤---Linux下的最新Git版本安装
原文地址:https://blog.csdn.net/u010887744/article/details/53957613 [标注大头] 1.查看当前git版本:git --version 查看最新 ...
- Mozilla开始推送Firefox Preview 5.0版 支持画中画特性
Mozilla 发布了 5.0 版本的 Firefox Preview 浏览器,根据 GitHub 上的发布说明,这次更新带来了一系列新的改进.其中包含对五个新的附加组件的支持,引入了对 Progre ...
- Json & pickle 数据序列化
前提: 文本文件中只能写入字符串或ascii码格式的内容. info={'name':'zoe','age':18} f=open('test.txt','w') f.write(info) #在文本 ...
- Java本地的项目,怎么可以让别人通过外网访问-内网穿透
2019独角兽企业重金招聘Python工程师标准>>> 一.点击链接 https://natapp.cn/ 注册个免费的账户 NATAPP官网 二.登陆进去以后查看authtoken ...