PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)

时间:2021-10-18 23:36:42
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.

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.

PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)

The above figure 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 S​3​​, we have 2 different shortest paths:

  1. PBMC -> S​1​​ -> S​3​​. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S​1​​ and then take 5 bikes to S​3​​, so that both stations will be in perfect conditions.

  2. PBMC -> S​2​​ -> S​3​​. 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: C​max​​ (≤), always an even number, is the maximum capacity of each station; N (≤), the total number of stations; S​p​​, 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 C​i​​ (,) where each C​i​​ is the current number of bikes at S​i​​ respectively. Then M lines follow, each contains 3 numbers: S​i​​, S​j​​, and T​ij​​ which describe the time T​ij​​ taken to move betwen stations S​i​​ and S​j​​. 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. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of S​p​​ 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,车站的数量n,问题车站sp,m条边,还有距离,求最短路径。如果最短路径有多个,求能带的最少的自行车数目的那条。如果还是有很多条不同的路,那么就找一个从车站带回的自行车数目最少的。带回的时候是不调整的

思路:

首先用dijkstra算法求出PBMC(0点)到目标点的最短距离。然后深搜穷举,每次深搜找到一条最短路径后依次记录路径上的各点,然后扫描,如果有的station少于最大容量的一半,带出的车数就加到take中;如果多了,带回去的车数加到back中。注意,每一站多的车辆只能放到后面一站去,而不能补充前面车站中少的数目。
在dfs中借助栈记录下最好的路径

#include<iostream>
#include<stack>
using namespace std; int maze[][];//迷宫
int vis[][];//记录迷宫中的某个位置是否访问过
int n,m; int dir[][] = {{,},{,-},{,},{-,}};//四个方向 struct point//位置
{
int x,y;
} p; stack<point> path,temp;//记录路径,temp是一个临时变量,和path一起处理路径 int count;//路径条数 void dfs(int x,int y)//x,y:当前位置
{
if(x==n- && y==m-)//成功---下面处理路径问题
{
cout << "******************路径"<< ++count << "******************" << endl;
while(!path.empty())//将path里面的点取出来,放在temp里面
{//path从栈顶-栈底的方向,路径是从终点-起点的顺序
point p1 = path.top();
path.pop();
temp.push(p1);
}
while(!temp.empty())
{//输出temp里面的路径,这样刚好是从起点到终点的顺序
point p1 = temp.top();
temp.pop();
path.push(p1);//将路径放回path里面,因为后面还要回溯!!!
cout << "(" << p1.x << "," << p1.y << ")" << endl;
}
return;
} if(x< || x>=n || y< || y>=m)//越界
return; //如果到了这一步,说明还没有成功,没有出界
for(int i=;i<;i++)//从4个方向探测
{
int nx = x + dir[i][];
int ny = y + dir[i][];//nx,ny:选择一个方向,前进一步之后,新的坐标
if(<=nx && nx<n && <=ny && ny<m && maze[nx][ny]== && vis[nx][ny]==)
{//条件:nx,ny没有出界,maze[nx][ny]=0这个点不是障碍可以走,vis[nx][ny]=0说明(nx,ny)没有访问过,可以访问 vis[nx][ny]=;//设为访问过
p.x = nx;
p.y = ny;
path.push(p);//让当前点进栈 dfs(nx,ny);//进一步探测 vis[nx][ny]=;//回溯
path.pop();//由于是回溯,所以当前点属于退回去的点,需要出栈
}
}
} int main()
{
count = ;
freopen("in.txt","r",stdin);//读取.cpp文件同目录下的名为in.txt的文件 p.x = ;
p.y = ;
path.push(p);//起点先入栈 cin >> n >> m;
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
vis[i][j] = ;
cin >> maze[i][j];
}
}
dfs(,); return ;
}

这个题目有两个比较坑的点:

1.仔细阅读题目,会发现其实有三个优先级判断点:题目正文中要求第一优先级为最短路径,第二优先级为派出自行车最少,而在结果输出中有第三优先级,即收回自行车最少。遗漏后两个优先级会导致有的点通不过;
2.在统计派出数和收回数时,要注意一个站点中多出来的自行车只能向后面的站点补充,而不能向前面的站点补充,这也是很容易忽视的问题。

我的样例:


 ->-> 

 ->->-> 

 ->->-> 

 ->->->-> 

 ->-> 

 ->->->-> 

AC代码:

 #include<bits/stdc++.h>
using namespace std;
int INF = ;
int C,SP,N,M;
int h[];//拥有多少自行车
int e[][];
int d[];
int v[];
int min_go=INF;//带去的越少越好
int min_back=INF;//带回来的越少越好
vector<int>p[];//记录所有最短路径中各个点的前一个有哪些
stack<int>route;
stack<int>final_route;
void clear(stack<int> &s){//清空栈
stack<int> empty;
swap(empty,s);
}
void dijstra()
{
d[]=;
memset(v,,sizeof(v));
for(int i=;i<=N;i++){
d[i]=e[][i];
if(d[i]!=INF)
{
p[i].push_back();
}
}
for(int i=;i<=N-;i++){
int k=-;
int min=INF;
for(int j=;j<=N;j++){
if(v[j]== && min>d[j]){
k=j;
min=d[j];
}
}
if(k==-){
break;
}
v[k]=;
for(int j=;j<=N;j++){
if(v[j]==){
continue;
}
if(d[j]>d[k]+e[k][j])
{
p[j].clear();
p[j].push_back(k);
d[j]=d[k]+e[k][j];
}
else if(d[j]==d[k]+e[k][j]){
p[j].push_back(k);
}
}
}
}
void dfs(int s,int go,int back){
for(int i=;i<p[s].size();i++){
int x=p[s].at(i);
if(x==){
if(min_go>go){//根据优先级更新!
min_go=go;
min_back=back;
final_route=route;//更新最终路线
final_route.push(x);
}else if(min_go==go && min_back>back){
min_go=go;
min_back=back;
final_route=route;//更新最终路线
final_route.push(x);
}
}else{
int g=go+C-h[x];
int b=back;//后面多的不能补到前面!
if(g<){//需要送去的为负数了
b+=(-*g);//反而还要带点回来
g=;//那就不送了
}
route.push(x);
dfs(x,g,b);
route.pop();
}
}
}
int main(){
cin>>C>>N>>SP>>M;
C/=;
for(int i=;i<=N;i++){
cin>>h[i];
p[i].clear();
}
for(int i=;i<=N;i++)
{
for(int j=;j<=N;j++)
{
if (i==j) e[i][j]=;
else e[i][j]=INF;
}
}
for(int i=;i<=M;i++){
int u,v,t;
cin>>u>>v>>t;
e[u][v]=e[v][u]=t;
}
dijstra(); int go=C-h[SP];
int back=;
if(go<){
back=-*go;
go=;
}
clear(route);
clear(final_route);
route.push(SP); dfs(SP,go,back);
//输出
cout<<min_go<<" ";
while(!final_route.empty()){
cout<<final_route.top();
final_route.pop();
if(!final_route.empty()){
cout<<"->";
}
}
cout<<" "<<min_back<<endl; return ;
}