0
点赞
收藏
分享

微信扫一扫

PAT.1018 Public Bike Management - 不只是Dijikstra

上古神龙 2022-03-11 阅读 40

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;
}                    
举报

相关推荐

0 条评论