AcWing 1137. Choose the best route(朴素dijkstra反向建图 or 虚拟源点法)

AcWing 1137. Choose the best route(朴素dijkstra反向建图 or 虚拟源点法)
AcWing 1137. Choose the best route(朴素dijkstra反向建图 or 虚拟源点法)
AcWing 1137. Choose the best route(朴素dijkstra反向建图 or 虚拟源点法)
AcWing 1137. Choose the best route(朴素dijkstra反向建图 or 虚拟源点法)

题目比较简单,讲两种做法

法一、二都是用的朴素dijkstra算法

法一:反向建图 求终点s到每个起点的最短距离 O(T * (n^2 + n))(T表示多组测试数据)820ms

#include <bits/stdc++.h>

using namespace std;
const int N = 1010, M = 2e4+10;
#define inf 0x3f3f3f3f
int g[N][N], dist[N];
bool st[N];
int n, m, s;
int w;
int W[N];

int dijk(int s){
        memset(dist, 0x3f, sizeof dist);
        memset(st, false, sizeof st);
        dist[s] = 0;
        for(int i=0;i<n;++i){
                int t = -1;
                for(int j=1;j<=n;++j){
                        if(!st[j]&&(dist[t]>dist[j]||t==-1)){
                                t = j;
                        }
                }
                st[t] = true;
                for(int j=1;j<=n;++j){
                        dist[j] = min(dist[j], dist[t] + g[t][j]);
                }
        }
        
        int res = inf;
        for(int i=0;i<w;++i){
                res = min(res, dist[W[i]]);//求终点s到所有起点最短路的最小值
        }
        
        return res;
}

int main()
{
        while(cin>>n>>m>>s)
        {
            memset(g, 0x3f, sizeof g);
            for(int i=0;i<m;++i){
                    int p, q, t;
                    cin>>p>>q>>t;
                    g[q][p] = min(g[q][p], t);//注意是反向建图,加入的边就要反转
            }
            cin>>w;
            for(int i=0;i<w;++i) cin>>W[i];
            int ans = dijk(s);
            if(ans==inf) cout<<-1<<endl;
            else cout<<ans<<endl;
        }
        
        return 0;
}

法二 设置虚拟源点 求虚拟源点到终点s的最短距离 O(T * n^2) 339ms

#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
#define inf 0x3f3f3f3f
int g[N][N], dist[N];
bool st[N];
int n, m, s;
int w;
int W[N];

int dijk(int s){
        memset(dist, 0x3f, sizeof dist);
        memset(st, false, sizeof st);
        dist[0] = 0;
        //由于加了一个点,因此每个for循环的次数都要加一
        for(int i=0;i<n+1;++i){
                int t = -1;
                for(int j=0;j<=n;++j){
                        if(!st[j]&&(dist[t]>dist[j]||t==-1)){
                                t = j;
                        }
                }
                st[t] = true;
                for(int j=0;j<=n;++j){
                        dist[j] = min(dist[j], dist[t] + g[t][j]);
                }
        }
        
        return dist[s];//返回虚拟源点到终点s的最短距离
}

int main()
{
        while(~scanf("%d%d%d", &n, &m, &s))
        {
            memset(g, 0x3f, sizeof g);
            for(int i=0;i<m;++i){
                    int p, q, t;
                    scanf("%d%d%d", &p, &q, &t);
                    g[p][q] = min(g[p][q], t);
            }
            scanf("%d", &w);
            for(int i=0;i<w;++i) scanf("%d", &W[i]), g[0][W[i]] = 0;//将虚拟源点到起点的距离都设置为0,因此所有起点到终点的最短路径就是虚拟源点到终点的最短路
            int ans = dijk(s);
            if(ans==inf) printf("-1\n");
            else printf("%d\n" ,ans);
        }
        
        return 0;
}

上一篇:聊聊如何将数据同步到apollo配置中心


下一篇:Tabulator 隐藏列示例