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,求多余或缺少的自行车的数量,再和全局最小值比较、更新
代码
// 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/
欢迎讨论和交流!