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

01 第一个容易想到的dfs (超时)

class Solution {
public:
    
    int res=INT_MAX;
    vector<vector<int>>G;
// dfs(cur,total,layer) 表示从src点开始到达cur ,cur(在第layer 层)
    void dfs(int cur,int total,int layer,vector<vector<int>> & fee,int K,int dst){
        if(layer>K+1) return;
        if(cur==dst){
            res=min(res,total);
            cout<<res<<endl;
            return;
        }
        for(auto v:G[cur]){
            dfs(v,total+fee[cur][v],layer+1,fee,K,dst);
        }
    }
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        G.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            G[e[0]].push_back(e[1]);
            fee[e[0]][e[1]]=e[2];
        }
        dfs(src,0,0,fee,K,dst);
        return  res==INT_MAX? -1:res;
    }
};

02 由上面得到下面的逆向dfs(超时)

// dfs(int cur,int layer,vector<vector<int>> & fee,int K,int dst)
//表示从cur 到dst的最小费用,当前cur位于第layer 层.
//因此只需要返回dfs(0,0,fee,K,dst)
class Solution {
public:
    
  
    vector<vector<int>>G;
    long long dfs(int cur,int layer,vector<vector<int>> & fee,int K,int dst){
        if(layer>K+1) return INT_MAX;
        if(cur==dst){
            return 0;
        }
        long long res=INT_MAX;
        for(auto v:G[cur]){
            
            res=min(fee[cur][v]+dfs(v,layer+1,fee,K,dst),res);
        }
        return res;
    }
    
    
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        G.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            G[e[0]].push_back(e[1]);
            fee[e[0]][e[1]]=e[2];
        }
        int ans=dfs(src,0,fee,K,dst);
        return  ans==INT_MAX? -1:ans;
    }
};

03 对上述的逆向dfs 做记忆化,可通过

class Solution {
public:
    vector<vector<int>>G;
    //dfs(cur,layer,dst) 表示cur(在layer层)到dst所需的最小花费,
    //记忆化搜索mem[cur][layer]表示从cur(在layer层)到dst所需的最小花费
    long long dfs(int cur,int layer,vector<vector<int>> & fee,int K,int dst,vector<vector<int>> & mem){
        if(layer>K+1) return INT_MAX;
        if(cur==dst){
            mem[cur][layer]=0;
            return 0;
        }
        if(mem[cur][layer]!=INT_MAX) return mem[cur][layer];
        long long res=INT_MAX;
        for(auto v:G[cur]){
            res=min(fee[cur][v]+dfs(v,layer+1,fee,K,dst,mem),res);
        }
        mem[cur][layer]=res;
        return res;
    }
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        G.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            G[e[0]].push_back(e[1]);
            fee[e[0]][e[1]]=e[2];
        }
        vector<vector<int>>  mem(n,vector<int>(K+2,INT_MAX));
        int ans=dfs(src,0,fee,K,dst,mem);
        return  ans==INT_MAX? -1:ans;
    }
};

在这里插入图片描述

04 可根扰逆向记忆化递归改写为DP 方法,下面以正向dp 为例,这里略

05 正向dfs


class Solution {
public: 
    vector<vector<int>>Parents;
    //dfs(cur,layer,dst) 表示从src到cur(在layer层)所需的最小花费,
    // 记忆化递规 mem[cur][k-1]
    long long dfs(int cur,vector<vector<int>> & fee,int K,int src){
        if(K<0) return INT_MAX;
        if(cur==src){
            return 0;
        }
        long long res=INT_MAX;
        for(auto v:Parents[cur]){
            res=min(fee[v][cur]+dfs(v,fee,K-1,src),res);
        }
        return res;
    }
    
    
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        Parents.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            // G[e[0]].push_back(e[1]);
            Parents[e[1]].push_back(e[0]);
            fee[e[0]][e[1]]=e[2];
        }
        int ans=dfs(dst,fee,K+1,src);
        return  ans==INT_MAX? -1:ans;
    }
};

06 对上面的做记忆化

class Solution {
public:
    
  
    vector<vector<int>>Parents;
    //dfs(cur,layer,dst) 表示从src到cur(在layer层)所需的最小花费,
    // 记忆化递规 mem[cur][k-1]
    long long dfs(int cur,vector<vector<int>> & fee,int K,int src,vector<vector<int>> & mem){
        if(K<0) return INT_MAX;
        if(cur==src){
            mem[cur][K]=0;
            return 0;
        }
        if(mem[cur][K]!=INT_MAX) return mem[cur][K];
        long long res=INT_MAX;
        for(auto v:Parents[cur]){
            res=min(fee[v][cur]+dfs(v,fee,K-1,src,mem),res);
        }
        mem[cur][K]=res;
        return res;
    }
    
    
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        Parents.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        // vector<vector<int>> & fee
        for( auto e:flights){
            // G[e[0]].push_back(e[1]);
            Parents[e[1]].push_back(e[0]);
            fee[e[0]][e[1]]=e[2];
        }
        vector<vector<int>>  mem(n,vector<int>(K+2,INT_MAX));
        int ans=dfs(dst,fee,K+1,src,mem);
        return  ans==INT_MAX? -1:ans;
    }
};

07 由上面得正向DP


class Solution {
public: 
   // dp[cur][layer]表示从src到cur(在layer层)所需的最小花费,
    vector<vector<int>>Parents;
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        Parents.resize(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            Parents[e[1]].push_back(e[0]);
            fee[e[0]][e[1]]=e[2];
        }
        vector<vector<long long>>  dp(n,vector<long long >(K+2,INT_MAX));
        for(int k=0;k<=K+1;k++)
            dp[src][k]=0;
        int cur;
        for(int k=1;k<=K+1;k++){
            for( cur=0;cur<n;cur++){
                if(dp[cur][k]!=INT_MAX) continue;
                for(auto v:Parents[cur]){
                    dp[cur][k]=min((fee[v][cur]+dp[v][k-1]),dp[cur][k]);
                }
            
            }
        }
        int ans=dp[dst][K+1];
        return  ans==INT_MAX? -1:ans;
    }
};

在这里插入图片描述

08 bfs 超时

class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        vector<vector<int>>G(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            G[e[0]].push_back(e[1]);
            fee[e[0]][e[1]]=e[2];
        }
        queue<vector<int>>q;
        q.push({src,0,0});// (cur,total,layer); 表示当前在cur 节点,第layer 层,累积和为total 
        int res=INT_MAX;
        while(!q.empty()){
            auto top=q.front();
            int cur=top[0];
            int total=top[1];
            int layer=top[2];
            q.pop();
            if(layer>K) break;
            for( auto v:G[cur]){
                if(v==dst) res=min(res,total+fee[cur][v]);
                q.push({v,total+fee[cur][v],layer+1});
            }
        }
        return  res==INT_MAX? -1:res;
    }
};

09bfs+优先队列

bool cmp(const vector<int> &a,const vector<int> &b){
    return a[1]>b[1];
}
class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
        vector<vector<int>>G(n);
        vector<vector<int>>fee(n,vector<int>(n,-1));
        for( auto e:flights){
            G[e[0]].push_back(e[1]);
            fee[e[0]][e[1]]=e[2];
        }   
        priority_queue<vector<int>,vector<vector<int>>,decltype (cmp) *>q(cmp);
        q.push({src,0,0});// (cur,total,layer);
        int res=INT_MAX;
        while(!q.empty()){
            auto top=q.top();
            int cur=top[0];
            int total=top[1];
            int layer=top[2];
            if(cur==dst) { return total; break;}

            q.pop();
            // cout<<cur<<endl;
            if(layer>K) continue;
            for( auto v:G[cur]){
                
                q.push({v,total+fee[cur][v],layer+1});
            }
        }                                                                                                                                                                
        return  res==INT_MAX? -1:res;
    }
};

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值