PAT(甲) 1018 Public Bike Management (30)(详解)

1018 Public Bike Management (30)

题目描述:

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.

这里写图片描述
Figure 1 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 S3, we have 2 different shortest paths:
1. PBMC -> S1 -> S3. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1 and then take 5 bikes to S3, so that both stations will be in perfect conditions.
2. PBMC -> S2 -> S3. 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.


  • 输入格式
    Each input file contains one test case. For each case, the first line contains 4 numbers: Cmax (<= 100), always an even number, is the maximum capacity of each station; N (<= 500), the total number of stations; Sp, 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 Ci (i=1,…N) where each Ci is the current number of bikes at Si respectively. Then M lines follow, each contains 3 numbers: Si, Sj, and Tij which describe the time Tij taken to move betwen stations Si and Sj. All the numbers in a line are separated by a space.

  • 输出格式
    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->S1->…->Sp. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of Sp 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.


题目大意:
这道题目主要有3个要求:
1. 到目标点的距离尽可能短
2. 从起点出发带的自行车尽量少
3. 如果在带的车相同的情况下,还有相同的路径,就选择带回的车最少的路径

解题方法:
dfs+dijstra 首先用狄杰斯特拉算法找出到目标点的最短路径,这里用vector来保存所有可能的路径。然后用dfs进行搜索,用另一个vector来保存路径(结合pop_back方法),当搜索到起点,就把路径取出,进行最少带回数和最少带来车辆数的比较,最后得出结果


易错点:
我自己犯的错误有
1. 在对图进行赋值时,没有双向赋值。
2. back清零和take计算位置弄反,导致错误。
另外还有可能犯的错误有
3. 在计算back和take时,对tempPath进行遍历的时候,必须要从尾遍历,否则back和take就会计算出错(因为这两者的计算是建立在运输方向上的)


程序:

#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
#define INF 65536
int dist[501];       /* 保存各点到原点的距离 */
int collect[501];    /* 保存各点的收录情况 */
int G[501][501];     /* 保存点之间的距离 */
int Cap[501];        /* 保存各点的车数-完美数量 */  
vector <int> path[501], tempPath, finalPath;
int back, take, MinBack = INF, MinTake = INF;

int FindMin(int N)
{   /* 寻找dist中最短路径 */
    int Min = INF, MinIdx = -1;
    for (int i = 0; i < N; i++)
        if (collect[i] == false && dist[i] < Min)
        {   /* 未被收录且当前距离最小 */
            Min = dist[i];
            MinIdx = i;
        }
    return MinIdx;
}

void dijstra(int N, int dest, int S)
{
    int V;
    for (int i = 0; i <= N; i++)
    {
        collect[i] = false; /* 初始化collect */
        dist[i] = G[0][i];  /* 初始化dist */
        path[i].push_back(0);   /* 初始化path */
    }
    path[S].clear();
    dist[S] = 0;    
    collect[S] = true;  /* 把起点放入集合 */
    while (1)
    {
        V = FindMin(N);
        if (V == -1 || V == dest) /* 如果找不到最短路或者已经到目标点就停止 */
            break;
        collect[V] = true;
        for (int i = 0; i <= N; i++)
            if (collect[i] == false && dist[V] + G[V][i] == dist[i])
                path[i].push_back(V);   /* 保存经过的路径 */
            else if (collect[i] == false && dist[V] + G[V][i] < dist[i])
            {
                path[i].clear();    /* 清空向量 */
                path[i].push_back(V);
                dist[i] = dist[V] + G[V][i];    /* 更新路径 */
            }
    }
}

void dfs(int S)
{
    tempPath.push_back(S);
    if (S == 0) /* 如果回到原点 */    
    {
        back = take = 0;
        for (int i = tempPath.size() - 1; i >= 0; i--)  /* 计算所需带的车和带回的车 必须反向遍历*/
        {
            int V = tempPath[i];    /* 路径的下标 */
            if (Cap[V] >= 0)    /* 如果该点车大于或等于完美状态 */
                back += Cap[V];
            else    /* 如果该点的车小于完美状态 */
            {
                if (back > -Cap[V])     /* 如果运输车上的余量大于经过点的缺少量 */
                    back += Cap[V];
                else
                {
                    take += -Cap[V] - back;
                    back = 0;
                }
            }   
        }
        if (take < MinTake)
        {
            MinTake = take;
            finalPath = tempPath;   /* 更新最佳路径 */
            MinBack = back;
        }
        else if (take == MinTake && back < MinBack)     /* 如果take相同,带回较少 */
        {
            finalPath = tempPath;   /* 更新最佳路径 */
            MinBack = back;
        }
        tempPath.pop_back();    /* 去掉末尾元素 */
        return;/*退出当前递归函数(如不理解可参阅:https://blog.csdn.net/invokar/article/details/80576362)*/
    }
    for (int i = 0; i < path[S].size(); i++)
        dfs(path[S][i]);
    tempPath.pop_back();    /* 弹出上行for循环的前驱顶点 */    
}

int main(int argc, char const *argv[])
{
    int C, N, dest, M, V1, V2, D;
    scanf("%d %d %d %d", &C, &N, &dest, &M);
    for (int i = 1; i <= N; i++){
        scanf("%d", &Cap[i]);   /* 输入每个点的自行车容量 */
        Cap[i] -= C/2;  /* 令每一个点的车辆数为当前车辆数-完美车辆数 */
    }
    for (int i = 0; i <= N; i++)
        for (int j = 0; j <= N; j++)
            G[i][j] = INF;
    for (int i = 0; i < M; i++)
    {
        scanf("%d %d %d", &V1, &V2, &D);
        G[V1][V2] = G[V2][V1] = D;  /* 建立边联系 */
    }
    dijstra(N, dest, 0);
    dfs(dest);
    printf("%d 0", MinTake);
    for (int i = finalPath.size() - 2; i >= 0 ; i--)    /* 倒着输出 */
        printf("->%d", finalPath[i]);
    printf(" %d\n", MinBack);
    return 0;
}

如果对您有帮助,帮忙点个小拇指呗~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值