题目

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 S​3 , we have 2 different shortest paths:

PBMC -> S​1​​ -> S​3​​ . In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S​1​​ and then take 5 bikes to S​3​​ , so that both stations will be in perfect conditions.PBMC -> S​2​​ -> S​3​​ . 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: C​max (≤100), always an even number, is the maximum capacity of each station; N (≤500), the total number of stations; S​p​​ , 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 S​i​​ respectively. Then M lines follow, each contains 3 numbers: S​i​​ , S​j​​ , and T​ij which describe the time T​ij​​ taken to move betwen stations S​i​​ and S​j​​ . 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​​ −>⋯−>S​p​​ . Finally after another space, output the number of bikes that we must take back to PBMC after the condition of S​p​​ 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分) 思路分析 + 满分代码的更多相关文章

  1. 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 ...

  2. 1018 Public Bike Management (30 分)

    There is a public bike service in Hangzhou City which provides great convenience to the tourists fro ...

  3. 1018 Public Bike Management (30分) PAT甲级真题 dijkstra + dfs

    前言: 本题是我在浏览了柳神的代码后,记下的一次半转载式笔记,不经感叹柳神的强大orz,这里给出柳神的题解地址:https://blog.csdn.net/liuchuo/article/detail ...

  4. 1018 Public Bike Management (30分) (迪杰斯特拉+dfs)

    思路就是dijkstra找出最短路,dfs比较每一个最短路. dijkstra可以找出每个点的前一个点, 所以dfs搜索比较的时候怎么处理携带和带走的数量就是关键,考虑到这个携带和带走和路径顺序有关, ...

  5. 【PAT甲级】1018 Public Bike Management (30 分)(SPFA,DFS)

    题意: 输入四个正整数C,N,S,M(c<=100,n<=500),分别表示每个自行车站的最大容量,车站个数,此次行动的终点站以及接下来的M行输入即通路.接下来输入一行N个正整数表示每个自 ...

  6. 1018 Public Bike Management (30)(30 分)

    时间限制400 ms 内存限制65536 kB 代码长度限制16000 B There is a public bike service in Hangzhou City which provides ...

  7. 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 ...

  8. 1018. Public Bike Management (30)

    时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue There is a public bike service i ...

  9. 1025 PAT Ranking (25分) 思路分析 +满分代码

    题目 Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of ...

随机推荐

  1. pickle\json,configparser,hashlib模块

    python常用模块 目录 python常用模块 json模块\pickle模块 configparser模块 hashlib模块 subprocess模块 json模块\pickle模块 首先说一下 ...

  2. Daily Scrum 12/29/2015

    Process: Zhaoyang: Add the Time bar feature in the APP and complete the Speech API. Yandong: Do some ...

  3. X - Ehab and Path-etic MEXs CodeForces - 1325C

    MMP,差一点就做对了. 题目大意:给你一个树,对这个树的边进行编号,编号要求从0到n-1,不可重复,要求MEX(U,V)尽可能的小, MEX(x,y)的定义:从x到y的简单路径上,没有出现的最小编号 ...

  4. C++写日志方法调试

    调试方法有很多 介绍一种奇怪的?调试方法哈哈 通过WriteLog记录返回值查看返回结果. string str_log;stringstream ssteam;ssteam << &qu ...

  5. Java工作流引擎-集团模式下的权限 设计与实现

    关键字 工作流开发框架权限设计.用户组.岗位.集团模式应用. java工作流程引擎, .net 工作流引擎,工作流开发框架 相关的表结构 -- 相关组织-表结构. SELECT No,Name,Par ...

  6. Linux-LAMP虚拟主机配置

    1.配置用户认证 <Directory /data/discuz/passwd> AllowOverride AuthConfig AuthName "自定义的" Au ...

  7. Win10桌面美化

    捯饬了几个小时终于捯饬好了,没什么特效,就是看起来干净了许多. 用到的小软件: 链接:https://pan.baidu.com/s/1_PSTn0JZ22ZGiMDOdvdWEw提取码:329c 1 ...

  8. 常用mysql 语句

    ALTER TABLE table_name AUTO_INCREMENT = 1;重置自增字段值从1开始 truncate table `table_name` 清空表,保留数据结构

  9. webpack3 babel相关

    babel 链接地址 在index.js中写入js6的语法如 let fn = (){ console.log('this is es6') } 执行npm run build 在打包出来的js文件中 ...

  10. 2019-2020-1 20199310《Linux内核原理与分析》第八周作业

    1.问题描述 在前面的文章中,学习了在Linux系统之中如何创建一个新进程进行追踪,本文将围绕编译链接的过程和ELF可执行文件格式,对Linux内核装载和启动一个可执行程序. 2.解决过程 2.1 E ...