acwing.342 道路とルート

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N = 25010,M = 150010,INF = 0x3f3f3f3f;
#define x first
#define y second
typedef pair<int,int> PII;

queue<int> q;
int e[M],w[M],h[N],ne[M],idx;
int din[N],bcnt,dist[N],id[N],st[N];
vector<int> block[N];
int n,mr,mp,s;

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

void dfs(int u,int bid)
{
    id[u] = bid;
    block[bid].push_back(u);
    
    for(int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if(!id[j]) dfs(j, bid);
    }
    
}

void dijkstra(int bid)
{
    priority_queue<PII,vector<PII>,greater<PII>> heap;
    
    for(int x : block[bid]) heap.push({dist[x],x});
    
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.y;
        
        if(st[ver])continue;
        st[ver] = true;
        
        for(int i = h[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                if(id[j] == bid) heap.push({dist[j],j});
            }
            
            if(id[j] != bid && --din[id[j]] == 0) q.push(id[j]);
        }
        
        
    }
    
}


void topsort()
{
    memset(dist, 0x3f, sizeof dist);
    dist[s] = 0;
    
    for(int i = 1; i <= bcnt; i ++ )
    {
        if(din[i] == 0) q.push(i);
    }
    
    while(q.size())
    {
        int t = q.front();q.pop();
        dijkstra(t);
        
    }
    
    
}

int main()
{
    memset(h, -1, sizeof h);
    cin >> n >> mr >> mp >> s;
    
    while( mr -- )
    {
        int a,b,c;cin >> a >> b >> c;
        add(a, b, c),add(b, a, c);
    }
    
    for(int i = 1; i <= n; i ++ )
    {
        if(!id[i]) dfs(i, ++ bcnt);
    }
    
    while( mp -- )
    {
        int a,b,c;cin >> a >> b >> c;
        add(a, b, c);
        din[id[b]] ++;
    }
    
    topsort();
    
    for(int i = 1; i <= n; i ++ )
    {
        if(dist[i] > INF / 2) puts("NO PATH");
        else printf("%d\n",dist[i]);
    }
    
    return 0;
}

以下は、2 種類のエッジを持つ加重有向グラフで単一ソースの最短経路問題を解くためのコードの一部です。最初のタイプのエッジは無向エッジで、mr バーで構成され、2 番目のタイプのエッジは有向エッジで、mp バーで構成されます。

アルゴリズムには主に2つのステップがあり、まず、元のグラフをいくつかの「ブロック」に分割し、各ブロック内のポイントに最初のタイプのエッジを介して直接到達できます。次に、ブロックごとにダイクストラ アルゴリズムを実行し、ブロック内のポイントの中で開始点に最も近いポイントを毎回取り出し、隣接するポイント間の距離を更新します。隣接するポイントは異なるブロックにある可能性があるため、ブロックごとにヒープを維持する必要があり、ヒープは最短経路を決定していないブロック内のポイントを格納することに注意してください。

次に、トポロジカル ソートを使用して、入次数 0 のブロックから開始するたびにすべてのブロックをトラバースし、ブロック内のすべての点の最短経路を見つけ、隣接するブロックの入次数を更新します。が 0 の場合、それをトポロジー的にソートされたキューに追加し、トラバーサルを待ちます。最後に、各点から開始点までの最短経路が取得されます。

特定の実装では、隣接リストを使用してグラフを保存し、ベクトルを使用して各ブロックのポイントを保存し、配列 dist を使用して開始点から各ポイントまでの最短パスの長さを記録し、配列 id を使用して各ポイントが属するブロックを記録し、配列 din を使用して記録します。各ブロックの次数については、配列 st を使用して、各ポイントがヒープに追加されたかどうかを記録します。

 

コードの詳細については、最初に dfs 関数で、現在のノード j の id が 0 の場合、j がどのブロックにも追加されていないことを意味するため、現在のブロックに追加する必要があり、dfs はjで実行されます。ここで、dfs 関数のビッドは、ターゲット ブロックの番号ではなく、現在のブロックの番号を表すことに注意してください。

次に、Dijkstra のアルゴリズムのヒープは STL の優先キューを使用し、そこに格納される要素は PII 型であり、現在のポイントの最短パス長とポイントの番号を表します。隣接するポイント間の距離が更新されるたびに、距離が以前の値よりも小さいポイントのみをヒープに追加する必要があることに注意してください。最小値なので、再度更新する必要はありません。

最後に、topsort 関数では、Dijkstra のアルゴリズムをブロックごとに 1 回実行する必要があるため、すべてのブロックをトラバースし、次数 0 のブロックをトポロジカルに並べ替える必要があります。トポロジカル ソートでは、ダイクストラのアルゴリズムをブロックごとに 1 回実行し、ブロック内のすべてのポイントの最短パスを更新し、隣接するブロックの次数を更新します。隣接ブロックの次数が 0 の場合、トポロジ的にソートされたキューに追加され、トラバーサルを待ちます。

注: ブロック内の隣接しない要素も距離によって更新できますが、dijkstra をヒープに実行する代わりに、topsort を実行します。

おすすめ

転載: blog.csdn.net/m0_66252872/article/details/129387130