PAT.1018 Public Bike Management - 不只是Dijikstra

本文探讨了一道关于公共自行车调度的算法问题,最初尝试使用Dijkstra算法求解,但发现无法同时优化路径长度和携带自行车的数量。作者随后改用深度优先搜索(DFS)配合前驱节点数组,成功找到最小携带自行车量的路径。在DFS过程中,作者考虑了起点满车和无车两种情况,并在每条路径上更新最小需求量。最终,通过清除Dijkstra过程中目标节点的前驱节点,确保找到最优解。
摘要由CSDN通过智能技术生成

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值