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.
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 S3, we have 2 different shortest paths:
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.
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.
10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1
3 0->2->3 0
PBMC will collect or send bikes to adjust the condition of that station to perfect.
一调节,必定达到完美状态第一行:
Cmax<100 N<500 Sp M
偶数容量 总站数 问题站编号 边条数
编号1~N
PBMC站0号第二行:
N个数 描述Si站现在有几辆车M行:描述边
Si Sj Tij 第i号站到第j号站总耗时 Tij
输出: 带出的车辆数 路径 带回的车辆数
第一条件: 路径最短(边权最小)
第二条件: 需要带出车:路径上 车的总数带出的车最少(点权最大)
第三条件:fullProblem 带出车都为0 此时
带回的车最少(点权最小)
每个点权都减去 Cmax/2 这样就可以通过点权正负来判断是需要补给还是需要带回
而且此时wight[0]也即是起点管理站也正好是处于不用处理的状态 也就不需要特判了
当然直接与Cmax/2比较也行,就是麻烦
dij+bfs 先由模板bfs求出最短路,然后dfs单独遍历所有的最短路径,vector
path存下所有结点,然后在 递归边界分支内对path逆序遍历就可以正序(也即起点0->终点Sp)遍历每个结点,初始need和remain都为0 到达一个结点,若wight<0,若remian够大,则直接减少remain,否则remian减为0,need增加(注意每次都要need+= remain+=),因为之前都有可能有库存或者需求(因为按顺序调整后面多得再多也无法搬运给前面的结点)。结束先根据need最小更新path(同时更新最终的minNedd和minBack).若need相等,则根据remain是否更小,更新path(同时更新minBack 最终minNeed相等不用更新)
#include
using namespace std;
const int INF=1e9;
const int maxn=510;
int G[maxn][maxn],n,C;
bool vis[maxn]={0};
int wight[maxn];//第i站有wight辆车
int d[maxn];//起点0到i结点的距离为d[i]
vector pre[maxn];//前驱 最短路径树
void dijstra(int s){
fill(d,d+maxn,INF);
d[0]=0;
//除了距离因素,其他的都不考虑 dij只求最短距离
for(int i=0;i path,tempPath;
void dfs(int s,int v){
if(s==v){//递归边界 到达起点
tempPath.push_back(v);
int need=0,remain=0;
for(int i=tempPath.size()-1;i>=0;i--){//记录路上结点的好处 可以逆序遍历使得结点顺序正过来
//cout<0){//不能一个变量累加得正负值 万一开始很多缺的,后面很多满的 后面的多余的解救不了前面的空缺
remain+=wight[id];
}else{//wight[id]<=0
if(remain>abs(wight[id])){
remain+=wight[id];
}else{
//注意需要补 千万注意是need+=而不是need=
//因为即使有remian也可能有need(先走的少了,开始没有库存,必须带 后面很多满的,就remain一大堆了)
need+=abs(wight[id])-remain;//少了 这是你要带的
remain=0;//肯定后置0呀
}
}
}
//此条路径遍历结束了 判断是否最优
if(need>C>>n>>Sp>>M;
for(int i=1;i<=n;i++){
cin>>wight[i];
wight[i]-=C/2;
}
wight[0]=0;
// for(int i=0;i<=n;i++) cout<>a>>b>>t;
G[a][b]=G[b][a]=t;
}
dijstra(0);
dfs(0,Sp);
cout<=0;i--){
if(i!=path.size()-1) cout<<"->";
cout<
其中一大部分都是模板死代码(除了一些题干的处理技巧)
#include
using namespace std;
const int INF=1e9;
const int maxn=510;
int G[maxn][maxn],n,C;
bool vis[maxn]={0};
int wight[maxn];//第i站有wight辆车
int d[maxn];//起点0到i结点的距离为d[i]
vector pre[maxn];//前驱 最短路径树
void dijstra(int s){
fill(d,d+maxn,INF);
d[0]=0;
//除了距离因素,其他的都不考虑 dij只求最短距离
for(int i=0;i path,tempPath;
void dfs(int s,int v){
if(s==v){//递归边界 到达起点
tempPath.push_back(v);
for(int i=tempPath.size()-1;i>=0;i--){//记录路上结点的好处 可以逆序遍历使得结点顺序正过来
//cout<>C>>n>>Sp>>M;
for(int i=1;i<=n;i++){
cin>>wight[i];
wight[i]-=C/2;
}
wight[0]=0;
// for(int i=0;i<=n;i++) cout<>a>>b>>t;
G[a][b]=G[b][a]=t;
}
dijstra(0);
dfs(0,Sp);
return 0;
}
剩下的部分,是本题的主逻辑