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 ...
随机推荐
- 遇到自己喜欢的视频无法下载,python帮你解决
问题描述 python是一种非常好用的爬虫工具.对于大多数的爬虫小白来说,python是更加简洁,高效的代码.今天就用实际案例讲解如何爬取动态的网站视频. 环境配置:python3:爬虫库reques ...
- stand up meeting 1/14/2016
part 组员 工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 主要对生词本卡片的整体设计做修改:协助主程序完成popup部分 ...
- U - Obtain a Permutation CodeForces - 1294E 思维
题解: 注意每一列与每一列之间互不影响,所以贪心地求出没一列的最小操作值,然后累加起来. 怎么求没一列的最小值呢?维护一个数组same表示其中same[i]=j表示将该序列向上翻滚i次有j个元素归位, ...
- Springboot:异步业务处理(十二)
说明 当正常业务处理调用一个复杂业务或者耗时较长的请求时,客户等待时间会比较长,造成不好的用户体验,所以这时候需要用的异步处理 构建一个群发邮件的service接口及实现(模拟) 接口:com\spr ...
- Docker 安装 Jenkins , 并解决初始安装插件失败
安装 Jenkins 后,初始化下载插件总是失败,导致安装不成功,重试好几次都是卡在安装插件那. 这里记录下 Docker 下怎么安装 Jenkins ,并解决初始安装插件失败问题. 安装插件失败,其 ...
- WebApi参数检查验证FluentValidation的使用方法
右键打开NuGet程序包管理,进入浏览,搜索 FluentValidation,点击下载 在Model文件夹添加一个Person类进行校验 校验前,using需要引入相应的命名空间方可使用,Abstr ...
- scrapy爬虫实例(1)
爬虫实例 对象 阳光问政平台 目标 : 主题,时间,内容 爬取思路 预先设置好items import scrapy class SuperspiderItem(scrapy.Item): title ...
- (第六篇)vim编辑器的使用
什么是 vim(window文本文档) Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.简单的来说, vi 是老式的字处理器,不过功 ...
- Data Flow Diagram with Examples - Customer Service System
Data Flow Diagram with Examples - Customer Service System Data Flow Diagram (DFD) provides a visual ...
- ansible的模块使用
转载于 https://www.cnblogs.com/franknihao/p/8631302.html [Ansible 模块] 就如python库一样,ansible的模块也分成了基本模块和 ...