PAT甲级1018Public Bike Management

题目链接

https://pintia.cn/problem-sets/994805342720868352/problems/994805489282433024

题解

题目要求

  • 如果有多个最短路径,则选择PBMC送出自行车的数量最少的路径

    如果还是有多条最短路径,那么就选择从车站带回的自行车数目最少的(带回的时候是不调整路过的车站的)

  • PBMC携带或者从经过的车站收集一定数量的自行车前往某车站,并使路过的车站都达到半满。

  • 输入

    • Cmax:不超过100,偶数,每个站点中最多有多少辆自行车
    • N:不超过500,站点的数量,站点索引为[1,N],PBMC索引为0
    • Sp:有问题的站点
    • M:边的数量
    • N个站点中自行车的数量
    • M条边
  • 输出

    • PBMC要送多少辆自行车
    • 路径
    • 要送多少辆自行车到PBMC

解题思路

PAT甲级1030Travel Plan和这题很类似,但比这题简单,大概是比这题少了一个DFS。

  • dijkstra

    除了要求出PBMC到所有结点的最短路径长度,还要在算法过程中记录所有最短路径上每个结点的前一个结点,进而进行下一步的DFS。

  • DFS

    运行dijkstra算法后,已经记录了所有最短路径上每个结点的前一个结点(可以有多个),然后从结点sp开始DFS,相当于从sp走到PBMC。

    DFS过程中要记录当前路径

  • 求路径上多余或缺少的自行车的数量

    DFS过程中,如果当前结点是PBMC,则从PBMC走到sp,求多余或缺少的自行车的数量,再和全局最小值比较、更新

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Problem: PAT Advanced 1018
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805489282433024
// Tags: 最短路 dijkstra BFS DFS 单源最短路 图

#include <iostream>
#include <climits>
#include <vector>
using namespace std;

const int INF = INT_MAX;
const int MAXN = 505;
int cmax, n, sp, m;
int minStationNeed = INF, minStationExtra = INF; // PBMC最少需要送出多少辆车,最少要送多少辆车到PBMC
int e[MAXN][MAXN]; // 车站间的距离
int dis[MAXN]; // PBMC到各车站的最短路径的长度
int extraBikeNum[MAXN]; // 各车站中有多少辆自行车是多余的
bool visited[MAXN]; // 是否已求出PBMC到各车站的最短路
vector<int> pre[MAXN]; // 在保证路径最短的前提下,最短路径中每个车站的前一个车站
vector<int> path;
vector<int> tempPath;

void dfs(int v){
// 遍历当前结点
tempPath.push_back(v);
if (v == 0){ // 此时已形成一条最短路径的逆序,存储在tempPath中
int stationNeed = 0, stationExtra = 0;
for (int i = tempPath.size() - 1; i >= 0; i--){
int u = tempPath[i];
if (extraBikeNum[u] > 0){ // 当前站点中自行车数量超过容量的一半,则可以送给后面的车站或者送回PBMC
stationExtra += extraBikeNum[u];
}
else if (extraBikeNum[u] < 0){ // 当前站点中自行车数量少于容量的一半
if (stationExtra + extraBikeNum[u] >= 0){ // 前边车站多出来的自行车足够使当前车站半满
stationExtra += extraBikeNum[u];
}
else{
stationNeed -= (stationExtra + extraBikeNum[u]);
stationExtra = 0;
}
}

}
if (stationNeed < minStationNeed){
path = tempPath;
minStationNeed = stationNeed;
minStationExtra = stationExtra;
}
else if (stationNeed == minStationNeed && stationExtra < minStationExtra){
path = tempPath;
minStationExtra = stationExtra;
}
}
// DFS
for (int i= 0; i < pre[v].size(); i++)
dfs(pre[v][i]);
// 回溯
tempPath.pop_back();
}

int main()
{
// 初始化
fill(e[0], e[0] + MAXN * MAXN, INF);
fill(dis, dis + MAXN, INF);

// 获取输入
scanf("%d %d %d %d", &cmax, &n, &sp, &m);
for (int i = 1; i <= n; i++){
scanf("%d", &extraBikeNum[i]);
extraBikeNum[i] = extraBikeNum[i] - cmax / 2;
}

int a, b, c;
for (int i = 0; i < m; i++){
scanf("%d %d %d", &a, &b, &c);
e[a][b] = e[b][a] = c;
}

dis[0] = 0; // PBMC为起点
for (int i = 0; i <= n; i++){
int u = -1, minDis = INF;
for (int j = 0; j <= n; j++){
if (!visited[j] && dis[j] < minDis){
minDis = dis[j];
u = j;
}
}
if (u == -1) break;
visited[u] = true;
for (int v = 0; v <= n; v++){
if (!visited[v] && e[u][v] != INF){
if (dis[u] + e[u][v] < dis[v]){
dis[v] = dis[u] + e[u][v];
pre[v].clear(); // 新的最短路径,所以要clear
pre[v].push_back(u); // u是v的最短路径中v的前一个车站
}
else if (dis[u] + e[u][v] == dis[v]){
pre[v].push_back(u); // u是v的最短路径中v的前一个车站
}
}
}
}

dfs(sp);
printf("%d 0", minStationNeed);
for (int i = path.size() - 2; i >= 0; i--)
printf("->%d", path[i]);
printf(" %d", minStationExtra);
return 0;
}

参考链接

https://blog.csdn.net/liuchuo/article/details/52316405


作者:@臭咸鱼

转载请注明出处:https://www.cnblogs.com/chouxianyu/

欢迎讨论和交流!