StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

AcWing1137. 选择最佳线路

题目传送门

题目大意

\(\qquad\)有一张有向图,可以有若干个起点,只有一个终点,求所有起点到终点的最短路中最短的一条,若所有起点都与终点不连通,则输出\(-1\)

解题思路

\(\qquad\)我们这题可以想出两个方面的思路:
\(\qquad\)\(1.\)我们可以设置虚拟源点\(S=0(这样编号不会与其他点冲突)\),连接\(S\)与所有的起点,边权都为\(0\),跑\(S\)到终点的最短路,这样最后得到的最短路就是题目所求
\(\qquad\)\(2.\)我们可以反向建图,然后跑从终点为源点的最短路,然后枚举所有起点,用全局变量\(res\)记录全局最小值。

为什么可以

\(\qquad\)因为虚拟源点\(S\)到所有起点的边权都为\(0\),所以从\(S\)开始不会改变最短路的长度,又因为它同时确保了原先作为起点的每个点都是可以出现在路径中的,所以我们用\(S\)做源点跑出来的最短路,就是所有起点到终点的最短路的最短的一条
\(\qquad\)此处,反向建图不做解释。

代码实现

这里提供四份代码
分别是
\(\qquad\)\(1.虚拟源点Dijkstra\)
\(\qquad\)\(2.虚拟源点SPFA\)
\(\qquad\)\(3.反向建图Dijkstra\)
\(\qquad\)\(4.反向建图SPFA\)
提醒:别忘记了初始化idx,清空邻接表和标记数组!!!

\(虚拟源点Dijkstra\)
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 1010, M = 40010, INF = 0x3f3f3f3f;
int h[N], w[M], e[M], ne[M], idx;
int n, m, T, dist[N], st[N], stn;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

void Dijkstra(int S) 
{
    memset(st, 0, sizeof st);
    memset(dist, 0x3f, sizeof dist);
    priority_queue<PII, vector<PII>, greater<> > heap;
    dist[S] = 0, heap.push({0, S});
    
    while (heap.size()) 
    {
        auto t = heap.top().second; heap.pop();
        
        if (st[t]) continue ;
        st[t] = true ; 
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) 
            {
                dist[j] = dist[t] + w[i];
                heap.push({dist[j], j});
            }
        }
    }
}

int main() 
{
    while (~scanf("%d%d%d", &n, &m, &T))
    {
        vector<int> stops; idx = 0;
        
        memset(h, -1, sizeof h);
        
        while (m -- )
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); //反向建图
        }
        
        int S = 0;
        scanf("%d", &stn);
        while (stn -- ) 
        {
            int x;
            scanf("%d", &x);
            add(S, x, 0);
        }
        
        Dijkstra(S);
        
        int res = dist[T];
        if (res == INF) puts("-1");
        else printf("%d\n", res);
    }
    
    return 0;
}
\(2.虚拟源点SPFA\)
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 1010, M = 40010, INF = 0x3f3f3f3f;
int h[N], w[M], e[M], ne[M], idx;
int n, m, T, dist[N], st[N], stn;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

void spfa(int S) 
{
    memset(st, 0, sizeof st);
    memset(dist, 0x3f, sizeof dist);
    queue<int> q;
    
    dist[S] = 0, st[S] = true, q.push(S);
    
    while (q.size()) 
    {
        auto t = q.front(); q.pop();
        st[t] = false ;
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) 
            {
                dist[j] = dist[t] + w[i];
                if (!st[j]) st[j] = true, q.push(j);
            }
        }
    }
}

int main() 
{
    while (~scanf("%d%d%d", &n, &m, &T))
    {
        vector<int> stops; idx = 0;
        
        memset(h, -1, sizeof h);
        
        while (m -- )
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); //反向建图
        }
        
        int S = 0;
        scanf("%d", &stn);
        while (stn -- ) 
        {
            int x;
            scanf("%d", &x);
            add(S, x, 0);
        }
        
        spfa(S);
        
        int res = dist[T];
        if (res == INF) puts("-1");
        else printf("%d\n", res);
    }
    
    return 0;
}
\(3.反向建图Dijkstra\)
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 1010, M = 40010, INF = 0x3f3f3f3f;
int h[N], w[M], e[M], ne[M], idx;
int n, m, T, dist[N], st[N], stn;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

void Dijkstra(int S) 
{
    memset(st, 0, sizeof st);
    memset(dist, 0x3f, sizeof dist);
    priority_queue<PII, vector<PII>, greater<> > heap;
    dist[S] = 0, heap.push({0, S});
    
    while (heap.size()) 
    {
        auto t = heap.top().second; heap.pop();
        
        if (st[t]) continue ;
        st[t] = true ; 
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) 
            {
                dist[j] = dist[t] + w[i];
                heap.push({dist[j], j});
            }
        }
    }
}

int main() 
{
    while (~scanf("%d%d%d", &n, &m, &T))
    {
        vector<int> stops; idx = 0;
        
        memset(h, -1, sizeof h);
        
        while (m -- )
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(v, u, w); //反向建图
        }
        scanf("%d", &stn);
        while (stn -- ) 
        {
            int x;
            scanf("%d", &x);
            stops.push_back(x);
        }
        
        Dijkstra(T);
        
        int res = INF;
        for (auto i : stops) res = min(res, dist[i]);
        if (res == INF) printf("%d\n", -1);
        else printf("%d\n", res);
    }
    
    return 0;
}
\(4.反向建图SPFA\)
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 1010, M = 40010, INF = 0x3f3f3f3f;
int h[N], w[M], e[M], ne[M], idx;
int n, m, T, dist[N], st[N], stn;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

void spfa(int S) 
{
    memset(st, 0, sizeof st);
    memset(dist, 0x3f, sizeof dist);
    queue<int> q;
    
    q.push(S), dist[S] = 0, st[S] = true ;
    
    while (q.size()) 
    {
        auto t = q.front(); q.pop();
        st[t] = false ; 
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) 
            {
                dist[j] = dist[t] + w[i];
                if (!st[j]) q.push(j), st[j] = true ;
            }
        }
    }
}

int main() 
{
    while (~scanf("%d%d%d", &n, &m, &T))
    {
        vector<int> stops; idx = 0;
        
        memset(h, -1, sizeof h);
        
        while (m -- )
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); //反向建图
        }
        
        int S = 0;
        scanf("%d", &stn);
        while (stn -- ) 
        {
            int x;
            scanf("%d", &x);
            add(S, x, 0);
        }
        
        spfa(S);
        
        int res = dist[T];
        if (res == INF) puts("-1");
        else printf("%d\n", res);
    }
    
    return 0;
}

\(\color{Green}{Accepted!}\)

posted @ 2022-12-23 14:27  StkOvflow  阅读(85)  评论(0)    收藏  举报