K 站中转内最便宜的航班(bfs最短路)

787. K 站中转内最便宜的航班

有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi。

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。

思路

不能直接用dijistra或者spfa用u的最短路更新邻点v,因为还要考虑经过的点数,它现在是到达u的最短路,但到达v的最短路不一定就是用u的最短路扩展来的,还可能是某一条到达u但所用点数少的路扩展而来

这也是本题的关键,我们不再用到达某一点的最短路径去更新它的邻点,而是用所有到达u的路径去更新u的邻点v
因为在本题多了一个另外的限制条件点数,所以可能不是最短路的所用的点数还可能更少,留给后面的点数更多到达的地方更多
而最短路可能用的点数要更多后面剩下的点数很少所以很多点可能通过走最短路还到不了,所以要用所有到u的路径去更新v而不是直接用最短路更新

代码

class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        queue<pair<int,int> > q;
        int dis[101],vis[101]; // dis[i]为从起点到i且经历不超过k个点的最短路径
        vector<int> w[101],e[101];
        for(auto& f:flights){
            e[f[0]].push_back(f[1]);
            w[f[0]].push_back(f[2]);
        }
        for(int i=0;i<=n;i++) dis[i]=1e6+10;
        dis[src]=0;
        q.push(make_pair(src,0));
        k=k+1;
        while(!q.empty()&&k--){ // 只有k个中转点
            int size=q.size();
            for(int i=0;i<size;i++){ //注意这里扩展的可能不是同一层,因为同层的1访问同层的2,此时2还在队列里层数为1,但1访问2之后2又多了一层变成了2,所以此时
            // 队列里其实有两个2,但是他们对应的到src的距离不同,这也是本题的关键,我们不再用到达某一点的最短路径去更新它的邻点,而是用所有到达u的路径去更新u的邻点v
            // 因为在本题多了一个另外的限制条件点数,所以可能不是最短路的所用的点数还可能更少,留给后面的点数更多到达的地方更多
            // 而最短路可能用的点数要更多后面剩下的点数很少所以很多点可能通过走最短路还到不了,所以要用所有到u的路径去更新v而不是直接用最短路更新
                int u=q.front().first,temp_d=q.front().second;
                q.pop();
                for(int i=0;i<e[u].size();i++){
                    int v=e[u][i];
                    int len=temp_d+w[u][i]; // 注意这里不是用的dis[u]+w[u][i],即不是用u的最短路来扩展的,而是用目前这条到u的实际路径长度扩展的
                    if(len<dis[v]){
                        dis[v]=len;
                        q.push(make_pair(v,len));
                    }
                }
            }
        }
        return dis[dst]==1e6+10?-1:dis[dst];
    }
};

错误示范
直接用最短路更新

class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        queue<int> q;
        int dis[101],vis[101];
        vector<int> w[101],e[101];
        // vector<vector<int> > e(101,vector<int>());
        // vector<vector<int> > w(101,vector<int>());
        for(auto& f:flights){
            e[f[0]].push_back(f[1]);
            w[f[0]].push_back(f[2]);
        }
        q.push(src);
        for(int i=0;i<=n;i++) dis[i]=1e6+10;
        dis[src]=0;
        vis[src]=1;
        k=k+1;
        while(k--){
            cout<<k<<endl;
            int len=q.size();
            for(int i=0;i<len;i++){ //注意这里不能直接用q.size()因为在装入数据时,q的大小一直在改变
                int u=q.front();
                q.pop();
                // vis[u]=0;
                for(int j=0;j<e[u].size();j++){
                    int v=e[u][j];
                    cout<<"v:"<<v<<endl;
                    if(dis[u]+w[u][j]<dis[v]&&dis[u]+w[u][j]<dis[dst]) { //必须是没有在队列里面的才能更新,否则路径长度就不是同一个数了
                        dis[v]=dis[u]+w[u][j]; //注意这里并不是要用目前到u的最短路去更新v,而是用所有可能到u的路径长度去更新v
                        // 因为其他非最短路虽然比较长,但可能中间经过的中转站数少于最短路,所以剩下的资源更多,也有可能成为到达dst的最短路在k的限定下
                        // if(!vis[v]) {
                        //     q.push(v);
                        //     vis[v]=1;
                        // }
                    }
                }
            }
        }
        return dis[dst]==1e6+10?-1:dis[dst];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值