[最短路径]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;
    }
};

你可能感兴趣的:(leetcode刷题,#,图论)