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/

欢迎讨论和交流!


posted @ 2020-09-18 13:55  臭咸鱼  阅读(141)  评论(0编辑  收藏  举报