PAT.1018 Public Bike Management - 不只是Dijikstra
题目链接
看到题目非常亢奋,我超,Dijikstra,然后越写越不对劲,似乎没法确保在求最短路的过程中保证出发带车量也是最少的,在不想大量修改代码的情况下在结构体里加入了站点原有车数,然后在优先队列里按距起点距离升序排列,等距按原有车数降序排列。
显然这样试过不了的,测试点67直接寄(这个处理办法没法解决路线上多个车量大于一半的站点)。
那没办法,只能抛弃在Dijikstra的过程中顺便求最少带车量的想法,用preNode数组来记录每个站在可能路径上的节点(每次最短路径更新时前驱站点都要清空),然后dfs搜索所有可能路径,给出最小带车量。
如果只用Dijikstra…
测试点67寄
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int volume,stationCnt,targetIndex,roadCnt,s,e,len;
int bikeCnt[505],path[505][505],vis[505],minDis[505],minCarry[505],currentCarry[505],preNode[505];
vector<int> neighbor[505];
struct node{
int index;
int dis;
int bike;
bool operator < (const node &a) const{
if(dis > a.dis) return true;
else if(dis == a.dis && bike < a.bike) return true;
else return false;
}
};
int main(){
cin>>volume>>stationCnt>>targetIndex>>roadCnt;
int halfVolume = volume / 2;
priority_queue<node> stations;
memset(minDis,0x3f3f3f3f,sizeof(minDis));
for(int i = 1 ; i <= stationCnt ; ++i) cin>>bikeCnt[i];
for(int i = 0 ; i < roadCnt ; ++i){
scanf(" %d %d %d",&s,&e,&len);
path[s][e] = path[e][s] = len;
neighbor[s].push_back(e);
neighbor[e].push_back(s);
}
stations.push((node){0,0,0});
while(!stations.empty()){
node currentStation = stations.top();
int currentIndex = currentStation.index;
int currentDis = currentStation.dis;
stations.pop();
if(vis[currentIndex] == 1) continue;
vis[currentIndex] = 1;
for(int nextIndex : neighbor[currentIndex]){
if(vis[nextIndex] == 0 && currentDis + path[currentIndex][nextIndex] < minDis[nextIndex]){
minDis[nextIndex] = currentDis + path[currentIndex][nextIndex];
preNode[nextIndex] = currentIndex;
if(currentCarry[currentIndex] + bikeCnt[nextIndex] < halfVolume){
//下一站车补不够的情况
currentCarry[nextIndex] = 0;
minCarry[nextIndex] = minCarry[currentIndex] - (currentCarry[currentIndex] + bikeCnt[nextIndex] - halfVolume);
}else{
//下一站车能补够的情况
currentCarry[nextIndex] = currentCarry[currentIndex] + bikeCnt[nextIndex] - halfVolume;
minCarry[nextIndex] = minCarry[currentIndex];
}
stations.push((node){nextIndex,currentDis + path[currentIndex][nextIndex],bikeCnt[nextIndex]});
}
}
}
stack<int> res;
int idx = targetIndex;
while(idx != 0){
res.push(idx);
idx = preNode[idx];
}
cout<<minCarry[targetIndex]<<" 0";
while(!res.empty()){
cout<<"->"<<res.top();
res.pop();
}
cout<<" "<<currentCarry[targetIndex];
}
题解
注意几点
- 我这种写法下dfs开始的currentNeed在终点站满车的情况下为0,无车的情况下为容量的一半
- Dijikstra过程中每次更新最短路目标节点的前驱节点都要清空。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int volume,halfVolume,stationCnt,targetIndex,roadCnt,s,e,len,minNeed = 0x3f3f3f3f;
int bikeCnt[505],path[505][505],vis[505],minDis[505];
vector<int> neighbor[505];
vector<int> preNode[505];
vector<int> res;
struct node{
int index;
int dis;
bool operator < (const node &a) const{
return dis > a.dis;
}
};
void findPath(int a,int currentNeed,vector<int> p){
if(a == 0){
if(currentNeed < minNeed){
minNeed = currentNeed;
res = p;
}
return;
}
for(int pre : preNode[a]){
int preNeed = (pre == 0) ? 0 : halfVolume - bikeCnt[pre];
p.push_back(a);
if(-preNeed >= currentNeed) findPath(pre,0,p);
else findPath(pre,preNeed + currentNeed,p);
p.pop_back();
}
}
int main(){
cin>>volume>>stationCnt>>targetIndex>>roadCnt;
halfVolume = volume / 2;
priority_queue<node> stations;
memset(minDis,0x3f3f3f3f,sizeof(minDis));
for(int i = 1 ; i <= stationCnt ; ++i) cin>>bikeCnt[i];
for(int i = 0 ; i < roadCnt ; ++i){
scanf(" %d %d %d",&s,&e,&len);
path[s][e] = path[e][s] = len;
neighbor[s].push_back(e);
neighbor[e].push_back(s);
}
stations.push((node){0,0});
while(!stations.empty()){
node currentStation = stations.top();
int currentIndex = currentStation.index;
int currentDis = currentStation.dis;
stations.pop();
if(vis[currentIndex] == 1) continue;
vis[currentIndex] = 1;
for(int nextIndex : neighbor[currentIndex]){
if(vis[nextIndex] == 0 && currentDis + path[currentIndex][nextIndex] < minDis[nextIndex]){
minDis[nextIndex] = currentDis + path[currentIndex][nextIndex];
preNode[nextIndex].clear();
preNode[nextIndex].push_back(currentIndex);
stations.push((node){nextIndex,currentDis + path[currentIndex][nextIndex]});
}else if(currentDis + path[currentIndex][nextIndex] == minDis[nextIndex]){
preNode[nextIndex].push_back(currentIndex);
}
}
}
//检查诸多路径中的最优解
findPath(targetIndex,bikeCnt[targetIndex] > halfVolume ? 0 : halfVolume - bikeCnt[targetIndex],{targetIndex});
cout<<minNeed<<" 0";
int pathLen = res.size();
for(int i = pathLen - 1 ; i > 0 ; --i) cout<<"->"<<res[i];
for(int i = pathLen - 1 ; i > 0 ; --i){
minNeed += bikeCnt[res[i]] - halfVolume;
}
cout<<" "<<minNeed;
}