pat甲级1018. Public Bike Management (30)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/richenyunqi/article/details/79550071

欢迎访问我的pat甲级题解目录哦https://blog.csdn.net/richenyunqi/article/details/79958195

1018. Public Bike Management (30)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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.

When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.


Figure 1

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.

Input Specification:

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.

Output Specification:

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.

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

题意分析:

每个车站的最大容量为一个偶数Cmax,如果车站中自行车的数量为Cmax/2,则认为该车站处于“完美状态”,如果有一个车站自行车数量为0或者为Cmax,则认为该车站有问题,从控制中心PBMC出发携带一定数量的自行车前往该车站,并在路上收集一些自行车,使得沿途的车站以及最终到达的问题车站达到“完美状态”,求出从PBMC到达该问题车站的最短路径,如果有多条,选择需要从PBMC携带自行车数量最少的路径;如果仍有多条,选择从问题车站带回自行车最少的。

算法设计:

利用Dijkstra算法求出所有距离最短的路径,并在从问题车站回溯到PBMC的DFS中选择符合要求的唯一的最短路径。为了编码方便,不妨在读入每个车站的自行车数量时都减去Cmax/2,如果仍为正表示该车站需要带回自行车,如果为负表示该车站需要从PBMC获取自行车。具体实现可见代码。

注意点:

1. 在选择路径时有三种选择条件,且优先级逐条递减:

(1)距离最短

(2)从PBMC携带自行车数量最少

(3)从问题车站带回自行车数量最少

2. 需要使得沿途所有车站都达到“完美状态”,而不仅是问题车站

3. 不能在Dijkstra中直接选择出唯一的路径,因为从PBMC携带自行车数量以及从问题车站带回自行车数量在路径上的传递不是简单的相加过程。只有当所有路径都确定后才能去选择最符合条件的那条路径

邻接表版C++代码:

#include<bits/stdc++.h>
using namespace std;
struct Edge{
    int v,cost;
    Edge(int vv,int c):v(vv),cost(c){}
};
int Cmax,N,Sp,M;//四个参数
int weight[505],dis[505];//每个城市现有自行车数量、存储最短距离
bool visit[505];//是否已被访问
vector<vector<int>>pathLast(505);//存储最短路径中每个节点的父节点
vector<vector<Edge>>graph(505);//存储图
vector<int>path,currentPath;//path存储最短路径,currentPath存储当前最短路径
int Sent=INT_MAX,Collect=INT_MAX;//Sent表示从PBMC携带自行车数量,Collect表示从问题车站带回自行车数量
void Dijkstra(){//迪杰斯特拉算法
    while(!visit[Sp]){//如果访问到了问题车站,跳出循环
        int v=-1,MIN=INT_MAX;//找出未访问的节点中距离最小的
        for(int i=0;i<N+1;++i)
            if(!visit[i]&&MIN>dis[i]){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//置该结点已访问
        for(Edge&e:graph[v])
            if(!visit[e.v]&&dis[e.v]>dis[v]+e.cost){//如果到达该结点的最短距离可更新成更短
                dis[e.v]=dis[v]+e.cost;//更新到达该结点的最短距离
                pathLast[e.v].clear();//更新目前最短路径中该结点的父节点
                pathLast[e.v].push_back(v);
            }else if(dis[e.v]==dis[v]+e.cost)//如果目前的路径与到达该结点的距离相等
                pathLast[e.v].push_back(v);//将当期路径中该结点的父节点压入
    }
}
void DFS(int v){//深度优先搜索
    if(v==0){//搜索到了PBMC结点
        int currentSent=0,currentCollect=0;//当前需要从PBMC携带自行车数量以及从问题车站带回自行车数量
        for(int i=currentPath.size()-1;i>=0;--i)//遍历当前的最短路径
            if(weight[currentPath[i]]>=0)//如果当前结点的自行车数量高于Cmax/2
                currentCollect+=weight[currentPath[i]];//将高于Cmax/2的自行车数量携带上
            else//如果当前结点的自行车数量低于Cmax/2
                if(currentCollect>=abs(weight[currentPath[i]])){//从路上携带的自行车多于当前结点需要补充的自行车数量
                    currentCollect+=weight[currentPath[i]];//将路上携带的自行车数量减去当前结点需要补充的自行车数量
                }else{//从路上携带的自行车少于当前结点需要补充的自行车数量
                    currentSent-=weight[currentPath[i]]+currentCollect;//需要在PBMC借出自行车
                    currentCollect=0;//路上携带的自行车数量置0
                }
        currentPath.push_back(v);//将PBMC结点压入当前最短路径
        if(currentSent<Sent){//当前路径从PBMC携带自行车数量更少
            Sent=currentSent;//更新各种参数
            Collect=currentCollect;
            path=currentPath;
        }else if(currentSent==Sent&&currentCollect<Collect){//当前路径从问题车站带回自行车数量更少
            Collect=currentCollect;//更新各种参数
            path=currentPath;
        }
        currentPath.pop_back();//弹出PBMC结点
        return ;
    }
    currentPath.push_back(v);//如果不是PBMC结点压入该结点
    for(int i=0;i<pathLast[v].size();++i)//遍历该结点的父节点,并递归调用深度优先遍历
        DFS(pathLast[v][i]);
    currentPath.pop_back();//弹出该结点
}
int main(){
    scanf("%d%d%d%d",&Cmax,&N,&Sp,&M);//读入四个参数
    for(int i=1;i<=N;++i){//读入每个车站自行车数量并减去Cmax/2
        scanf("%d",&weight[i]);
        weight[i]-=Cmax/2;
    }
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a].push_back(Edge(b,c));
        graph[b].push_back(Edge(a,c));
    }
    fill(dis+1,dis+N+1,INT_MAX);//将最短距离置为最大值
    dis[0]=0;//PBMC结点最短距离为0
    Dijkstra();//调用Dijkstar算法
    DFS(Sp);//深度优先搜索
    printf("%d ",Sent);//进行输出
    for(int i=path.size()-1;i>=0;--i)
        printf("%s%d",i<path.size()-1?"->":"",path[i]);
    printf(" %d",Collect);
    return 0;
}

邻接矩阵版c++代码:

#include<bits/stdc++.h>
using namespace std;
int Cmax,N,Sp,M;//四个参数
int weight[505],dis[505];//每个城市现有自行车数量、存储最短距离
bool visit[505];//是否已被访问
vector<vector<int>>pathLast(505);//存储最短路径中每个节点的父节点
int graph[505][505];//存储图
vector<int>path,currentPath;//path存储最短路径,currentPath存储当前最短路径
int Sent=INT_MAX,Collect=INT_MAX;//Sent表示从PBMC携带自行车数量,Collect表示从问题车站带回自行车数量
void Dijkstra(){//迪杰斯特拉算法
    while(!visit[Sp]){//如果访问到了问题车站,跳出循环
        int v=-1,MIN=INT_MAX;//找出未访问的节点中距离最小的
        for(int i=0;i<N+1;++i)
            if(!visit[i]&&MIN>dis[i]){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//置该结点已访问
        for(int i=0;i<N+1;++i)
            if(!visit[i]&&graph[v][i]!=0&&dis[v]+graph[v][i]<dis[i]){//如果到达该结点的最短距离可更新成更短
                dis[i]=dis[v]+graph[v][i];//更新到达该结点的最短距离
                pathLast[i].clear();//更新目前最短路径中该结点的父节点
                pathLast[i].push_back(v);
            }else if(graph[v][i]!=0&&dis[v]+graph[v][i]==dis[i])//如果目前的路径与到达该结点的距离相等
                pathLast[i].push_back(v);//将当期路径中该结点的父节点压入
    }
}
void DFS(int v){//深度优先搜索
    if(v==0){//搜索到了PBMC结点
        int currentSent=0,currentCollect=0;//当前需要从PBMC携带自行车数量以及从问题车站带回自行车数量
        for(int i=currentPath.size()-1;i>=0;--i)//遍历当前的最短路径
            if(weight[currentPath[i]]>=0)//如果当前结点的自行车数量高于Cmax/2
                currentCollect+=weight[currentPath[i]];//将高于Cmax/2的自行车数量携带上
            else//如果当前结点的自行车数量低于Cmax/2
                if(currentCollect>=abs(weight[currentPath[i]])){//从路上携带的自行车多于当前结点需要补充的自行车数量
                    currentCollect+=weight[currentPath[i]];//将路上携带的自行车数量减去当前结点需要补充的自行车数量
                }else{//从路上携带的自行车少于当前结点需要补充的自行车数量
                    currentSent-=weight[currentPath[i]]+currentCollect;//需要在PBMC借出自行车
                    currentCollect=0;//路上携带的自行车数量置0
                }
        currentPath.push_back(v);//将PBMC结点压入当前最短路径
        if(currentSent<Sent){//当前路径从PBMC携带自行车数量更少
            Sent=currentSent;//更新各种参数
            Collect=currentCollect;
            path=currentPath;
        }else if(currentSent==Sent&¤tCollect<Collect){//当前路径从问题车站带回自行车数量更少
            Collect=currentCollect;//更新各种参数
            path=currentPath;
        }
        currentPath.pop_back();//弹出PBMC结点
        return ;
    }
    currentPath.push_back(v);//如果不是PBMC结点压入该结点
    for(int i=0;i<pathLast[v].size();++i)//遍历该结点的父节点,并递归调用深度优先遍历
        DFS(pathLast[v][i]);
    currentPath.pop_back();//弹出该结点
}
int main(){
    scanf("%d%d%d%d",&Cmax,&N,&Sp,&M);//读入四个参数
    for(int i=1;i<=N;++i){//读入每个车站自行车数量并减去Cmax/2
        scanf("%d",&weight[i]);
        weight[i]-=Cmax/2;
    }
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a][b]=graph[b][a]=c;
    }
    fill(dis+1,dis+N+1,INT_MAX);//将最短距离置为最大值
    dis[0]=0;//PBMC结点最短距离为0
    Dijkstra();//调用Dijkstar算法
    DFS(Sp);//深度优先搜索
    printf("%d ",Sent);//进行输出
    for(int i=path.size()-1;i>=0;--i)
        printf("%s%d",i<path.size()-1?"->":"",path[i]);
    printf(" %d",Collect);
    return 0;
}

阅读更多

扫码向博主提问

日沉云起

用最短的代码,写最快的算法
  • 擅长领域:
  • 算法
去开通我的Chat快问
换一批

没有更多推荐了,返回首页