PAT_甲级_1018 Public Bike Management (30分) (C++)【Dijkstra保存多条最短路径信息+DFS】

目录

1,题目描述

题目大意

输入

输出

2,思路

数据结构

关键点

1,求0到目的地的所有最短路径

2,遍历最短路径更新minNeed和minBack

3,代码


1,题目描述

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出发,到达目的地的最短路径,若有多条最短路径,判优办法是:使沿途的站点(包括目的地)达到完美状态(站点有半数自行车,多的取出,少的补上),需要最少自行车数目的路径。

输入

第一行(4个正数):C:各个站点的容量(偶数<=100),N:站点数目(<=500),S:有问题的站点编号(编号1-N,PBMC为0),M:路的数目;

第二行:有N个数,表示各站点当前自行车数目;

剩余M行:路的两端站点的编号

输出

PBMC需要送出的自行车数目,输出路径(0->......),调整至完美状态后需送回PBMC的自行车数目

2,思路

这道题目看似简单,实则杀机四伏。。。还是拜读了柳神大大的解题思路。

使用dijstra算法,算出PBMC(节点0)到其余所有节点的所有最短路径。 以目的节点为根节点,节点0为叶节点(所有路径的叶节点都是节点0),使用DFS算法,遍历所有最短路径,并计算和更新minNeed与minBack。

数据结构

  • vector<int> pre[502]:存放每个节点的前驱节点,以此来代表路径。500多个节点,每个节点均声明为一个容器;
  • vector<int> path, tempPath:在dfs时,存放暂时路径以及最终路径;
  • int graph[502][502], dis[502], weight[502]:存放图,0距各站点的最短距离,各个站点的自行车数目状况;

关键点

将问题划分成两个部分:求0到目的地的所有最短路径,遍历最短路径更新minNeed和minBack。

1,求0到目的地的所有最短路径

  • 利用Dijkstra算法求最短路径:(核心内容)1,限制最外层遍历的次数(每遍历一次,确定一个点);2,寻找dis数组未遍历过的节点中的最近节点u(相对于节点0);遍历与u相邻的且未访问过节点,更新dis数组,与路径信息;
  • 利用vector<int> pre存放路径信息(使用vector便于将多个最短路径存放在一起pre[v].push_back(u));

2,遍历最短路径更新minNeed和minBack

  • 利用DFS算法,遍历从目的节点(根节点)出发的所有最短路径,并记录tempPath;
  • 当到达叶节点时,tempPath记录的即为最短路径的一种。遍历tempPath,计算need与back,并更新minNeed、minBack以及path;
  • 遍历完所有最短路径之后,minNeed、minBack以及path即为最终结果;

3,代码

#include<iostream>
#include<stdio.h>
#include<vector>
#include<map>
#include<climits>
#include<algorithm>
using namespace std;

int c, n, s, m;                                 //c站点容量 n站点总数 s目的站点 m路的数目
int graph[502][502], dis[502], weight[502];
bool visited[502];
vector<int> pre[502];                           //记录路径
vector<int> path, tempPath;
int minNeed = INT_MAX, minBack = INT_MAX;

void dfs(int v){                                //从目的节点为根节点的树 叶节点只有一个统一为0
    tempPath.push_back(v);
    if(v == 0){                                 //已经从目的地点到达起始点(相当于叶节点)
        int need = 0, back = 0;
        for(int i = tempPath.size() - 1; i >= 0; i-- ){
            int id = tempPath[i];
            if(weight[id] > 0){
                back += weight[id];             //此站点超过完美状态 需要搬走
            }else{
                if(back > (0 - weight[id])){    //此站点未达完美状态 需要补给
                    back += weight[id];         //weight[id]<0
                }else{
                    need += (0 - weight[id] - back);
                    back = 0;
                }
            }
        }
        if(need < minNeed){
            minNeed = need;
            minBack = back;
            path = tempPath;
        }else if(need == minNeed && back < minBack){//若需从PBMC搬运的车数相同 则选择搬回PBMC车数最少的路径
            minNeed = need;
            minBack = back;
            path = tempPath;
        }
        tempPath.pop_back();                        //!!!将栈中的0弹出
        return;
    }
    for(int i = 0; i < pre[v].size(); i++)          //遍历所有路径
        dfs(pre[v][i]);
    tempPath.pop_back();                            //当一个节点的子节点全部处理完毕后 需要将其弹出 处理与它同一层的下一个节点
}

int main(){
//#ifdef ONLINE_JUDGE
//#else
//    freopen("1.txt", "r", stdin);
//#endif

    scanf("%d%d%d%d", &c, &n, &s, &m);
    fill(dis, dis + 502, INT_MAX);
    fill(graph[0], graph[0] + 502 * 502, INT_MAX);

    for(int i = 1; i <= n; i++){
        scanf("%d", &weight[i]);
        weight[i] -= c / 2;                             //正数:超出完美状态 负数:低于完美状态
    }

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

    dis[0] = 0;                                         //起始点是哪个 哪个就置为0
    for(int i = 0; i <= n; i++){                        //n个自行车站点 1个PBMC
        int minDis = INT_MAX;
        int u = -1;
        for(int j = 0; j <= n; j++){                    //找出距离起始点最近的点 初始时起始点距自己最近(为0)
            if(visited[j] == false && dis[j] < minDis){
                u = j;
                minDis = dis[j];
            }
        }
        if(u == -1) break;                              //所有节点都遍历过 或者不是联通图
        visited[u] = true;

        for(int v = 0; v <= n; v++){                    //更新与u相连 且 起始点->u->v距离 小于起始点->v 的节点
            if(visited[v] == false && graph[u][v] < INT_MAX){//节点未访问过 且有通路
                if(dis[v] > minDis + graph[u][v]){
                    dis[v] = minDis + graph[u][v];
                    pre[v].clear();                     //更新最短路径
                    pre[v].push_back(u);
                }
                else if(dis[v] == minDis + graph[u][v]){
                    pre[v].push_back(u);                //保存所有最短路径信息
                }
            }
        }
    }

    dfs(s);                                             //以目的节点为起始点 遍历它的所有最短路径(类似于一个树 不过叶节点只有一个 即0)
    printf("%d 0", minNeed);
    for(int i = path.size() - 2; i >= 0; i--){          //path.size() - 1位置处是0 上个printf中已经输出
        printf("->%d", path[i]);
    }
    printf(" %d", minBack);
    return 0;
}
发布了45 篇原创文章 · 获赞 5 · 访问量 2183

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/104258212