leetcode-787

题意分析

787. K 站中转内最便宜的航班 - 力扣(LeetCode)

       这道题乍一看就是一个加了限制的dijkstra算法,硬改的话到每个节点的最短距离数组要变成二维,表示走了的站数和对应的最短距离,超过的站数部分就不要了。不过最好的解法是bellman-ford,这个算法就是以边来限定顶点的最短距离,而且最多遍历n-1次就能取得每个顶点的最短路径。

        问题是更新k次,与满足最大中转站数为k站有什么关系吗?

        可以以最坏的情况考虑,每次遍历只能更新一个站,那么由等式

                                     dist[i][y]=min(dist[i][y],dist[i-1][x]+d);

其中i为遍历次数,y为当前要更新的顶点,x为与y相邻的前一个顶点。可以发现每次遍历y与起始点都可能会“插入”一个x来使距离更短,就相当于插入了一个中转站。所以遍历k次到终点的最大中转站只能是k个。

        那如果每次遍历都能更新多个站呢,那也是一层内的更新,相当于多个最坏情况的子树,所以最大中转站还是k个。

算法思路

        bellman-ford算法就是给定更新层数,每次都把边遍历一遍,找可以更新的边权值。由于最大为k个中转站,也就是说路上有k+2个顶点(包起终点),那么就只要k+1次遍历就一定能更新完路径,只要是连通的就可得解。

代码实现

class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        const int inf=INT_MAX/2;
        vector<vector<int>> dist(k+2,vector<int>(n,inf));
        dist[0][src]=0;
        int res=inf;
        for(int t=1;t<=k+1;t++){
            for(auto & fly:flights){
                int a=fly[0],b=fly[1],c=fly[2];
                dist[t][b]=min(dist[t][b],dist[t-1][a]+c);//前一顶点之前的遍历结果+当前边权
                if(b==dst) res=min(res,dist[t][b]);
            }
        }
        return res==inf?-1:res;
    }
};

错误样例

typedef pair<int,int> PII;
typedef array<int,3> AI3;
class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        const int inf=INT_MAX/2;
        vector<vector<int>> dist(k+2,vector<int>(n,inf));
        vector<vector<PII>> g(n);
        for(auto & f:flights){
            int a=f[0],b=f[1],c=f[2];
            g[a].emplace_back(c,b);
        }
        queue<AI3> q;
        q.push({0,src,0});     
        int res=inf;
        int step=0;
        while(step<k+1){
            step++;
            int size=q.size();
            while(size--){
                auto [d,i,t]=q.front();q.pop();
                dist[t][i]=min(dist[t][i],d);
                for(auto & [w,nxt]:g[i]){
                    if(t+1>k+1) continue; 
                    dist[t+1][nxt]=min(dist[t+1][nxt],d+w);
                    q.push({d+w,nxt,t+1});      
                }                     
            }     
        }
        for(int i=0;i<=k+1;i++){
            res=min(res,dist[i][dst]);
        }
        return res==inf?-1:res;
    }
};

        我觉着就是个层序遍历,多加个次数维度,次数大了就甩掉,但是运行超时了 。。。可能层序遍历枚举情况太多了吧。。。以后再来改吧。

解题总结

        bellman-ford算法适合负权、带限制顶点数的图。相关练习会另外补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值