[最短路徑]leetcode1334:閾值距離內鄰居最少的城市(medium)

題目:

1334. 閾值距離內鄰居最少的城市

題解:

最短路徑模板題:Bellman-Ford算法、Dijkstra算法、SPFA算法、Floyd-Warshall算法。

代碼如下:

class Solution {
public:
    //最短路徑的練手題,哈哈,不錯,剛在複習圖算法,這就來寫
    //題解1:floyd算法,時間複雜度O(n^3),三維dp,不過爲了簡化將三維dp簡化爲二維dp罷了,具體可參考《挑戰程序設計競賽》
    int findTheCity_1(int n, vector<vector<int>>& edges, int distanceThreshold) {
        //1、建立並初始化dp數組,若(i,j)之間存在邊,dp[i][j]則爲邊ij的權值,否則爲0x3f3f3f3f
        int dp[n][n];
        memset(dp,0x3f,sizeof(dp));
        for(const auto& edge:edges){
            dp[edge[0]][edge[1]]=dp[edge[1]][edge[0]]=edge[2];
        }
        //2、開始進行floyd算法求dp數組
        for(int k=0;k<n;++k){
            for(int i=0;i<n;++i){
                for(int j=0;j<n;++j){
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
                }
            }
        }
        //3、求解最後結果
        int res=0,minNum=INT_MAX;
        for(int i=0;i<n;++i){
            int count=0;
            //計算i的鄰居城市中小於等於distance的城市個數
            for(int j=0;j<n;++j){
                if(i!=j&&dp[i][j]<=distanceThreshold){
                    count++;
                }
            }
            //城市i的鄰居城市距離小於distance的城市個數更少,則更新爲更小的城市的數目。
            //由於i是逐漸增大的,所以在滿足題意得要求下,我們更新更大的i爲res。
            if(count<=minNum){
                minNum=count;
                res=i;
            }
        }
        return res;
    }

    //題解2:Bellman-Ford算法,時間複雜度爲O(V^2 * E)
    int findTheCity_2(int n,vector<vector<int>>& edges,int distanceThreshold){
        //1、初始化dist,dist表示頂點k到達其他所有頂點的最短路徑
        int dist[n];
        memset(dist,0x3f,sizeof(dist));
        int t=edges.size();
        //2、補充有向圖爲無向圖
        for(int i=0;i<t;++i){
            edges.push_back({edges[i][1],edges[i][0],edges[i][2]});
        }
        //表示結果first,second表示小於等於閾值的最小城市數,和該城市的起始編號
        pair<int,int> res(0x3f3f3f3f,n);
        //3、bellman-ford算法:源點k出發的最短路徑
        for(int k=0;k<n;++k){
            dist[k]=0;
            //由於最短路不會經過同一頂點兩次,所以最短路最多有n-1條邊,因此有些時候可以利用這個性質檢查圖是否存在負圈
            for(int j=0;j<n-1;++j){
                for(int i=0;i<edges.size();++i){
                    int a=edges[i][0],b=edges[i][1],w=edges[i][2];
                    //更新邊ab,終點b的最短路徑值
                    if(dist[a]!=0x3f3f3f3f&&dist[b]>dist[a]+w){
                        dist[b]=dist[a]+w;
                    }
                }
            }
            //統計從頂點k出發的最短路徑小於閾值的城市個數
            int count=0;
            for(int i=0;i<n;++i)if(dist[i]<=distanceThreshold)count++;
            //更小最小城市數和起始編號,由於k是連續變大的,所以在路徑相同時,會選用編號最大的
            if(count<=res.first){
                res.first=count;
                res.second=k;
            }
            //重置dist,進行下一次搜索從k+1頂點出發的最短路
            memset(dist,0x3f,sizeof(dist));
        }
        return res.second;
    }

    //題解3:dijkstra算法,時間複雜度O((V+E)*logV),數值插入和最小值取出使用小根堆,這樣來降低複雜度
    int findTheCity_3(int n,vector<vector<int>>& edges,int distanceThreshold){
        //1、初始化dist,dist表示從源點s出發到達其他頂點的最短路
        int dist[n];
        memset(dist,0x3f,sizeof(dist));
        //2、構建鄰接表
        map<int,set<pair<int,int>>> adjacent;
        for(const auto& edge:edges){
            int a=edge[0],b=edge[1],w=edge[2];
            adjacent[a].insert(make_pair(b,w));
            adjacent[b].insert(make_pair(a,w));
        }
        //res的first爲最小城市數,second爲城市編號
        pair<int,int> res(0x3f3f3f3f,0);
        //3、進行dijkstra算法,求源點s出發的最短路徑
        for(int s=0;s<n;++s){
            memset(dist,0x3f,sizeof(dist));
            dist[s]=0;
            //pair的first表示最短路徑,second表示源點s
            priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;//小根堆
            q.push(make_pair(0,s));
            while(!q.empty()){
                pair<int,int> p=q.top();q.pop();
                int v=p.second;
                if(dist[v]<p.first)continue;//取出的最小值不是最短距離,丟棄該值
                for(const auto& edge:adjacent[v]){//遍歷頂點v的鄰接點,進而更新頂點v的鄰節點的最短距離
                    //更新頂點v的鄰接點的最短距離,並添加到q中,first爲頂點v的鄰接點,second爲邊v first的權值
                    if(dist[edge.first]>dist[v]+edge.second){
                        dist[edge.first]=dist[v]+edge.second;
                        q.push(make_pair(dist[edge.first],edge.first));
                    }
                }
            }
            //統計從源點s出發小於等於閾值的城市數
            int count=0;
            for(int i=0;i<n;++i)if(dist[i]<=distanceThreshold)count++;
            //更新城市數和城市編號
            if(count<=res.first){
                res.first=count;
                res.second=s;
            }
        }
        return res.second;
    }

    //題解4:spaf算法,與dijkstra算法類似,不過是bf算法的優化,使用雙端隊列存放節點
    int findTheCity(int n,vector<vector<int>>& edges,int distanceThreshold){
        //1、初始化dist,dist表示從源點s出發到達其他頂點的最短路,visit用來標記頂點是否被訪問
        int dist[n],visit[n];
        memset(dist,0x3f,sizeof(dist));
        //2、構建鄰接表,first爲鄰接點頂點,second爲權值
        map<int,set<pair<int,int>>> adjacent;
        for(const auto& edge:edges){
            int a=edge[0],b=edge[1],w=edge[2];
            adjacent[a].insert(make_pair(b,w));
            adjacent[b].insert(make_pair(a,w));
        }
        //res的first爲最小城市數,second爲城市編號
        pair<int,int> res(0x3f3f3f3f,0);
        //3、spaf算法:從源點s出發尋找最短路徑
        for(int s=0;s<n;++s){
            //初試化路徑和visit數組
            memset(dist,0x3f,sizeof(dist));
            memset(visit,false,sizeof(visit));
            dist[s]=0;visit[s]=true;
            queue<int> q;
            q.push(s);
            while(!q.empty()){
                int u=q.front();q.pop();
                visit[u]=false;//設置頂點u不在隊列中
                for(const auto edge:adjacent[u]){//遍歷頂點u的鄰接點v
                    int v=edge.first,w=edge.second;
                    if(dist[v]>dist[u]+w){//更新頂點v的最小距離
                        dist[v]=dist[u]+w;
                        if(!visit[v]){
                            q.push(v);
                            visit[v]=true;
                        }
                    }
                }
            }
            //統計從源點s出發小於等於閾值的城市數
            int count=0;
            for(int i=0;i<n;++i)if(dist[i]<=distanceThreshold)count++;
            //更新城市數和城市編號
            if(count<=res.first){
                res.first=count;
                res.second=s;
            }
        }
        return res.second;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章