1. 程式人生 >實用技巧 >其它 >CodeForces1473E 分層圖 + 最短路

CodeForces1473E 分層圖 + 最短路


技術標籤:題解acm競賽codeforces

定義一條路徑上的值為 ∑ i = 1 k w e i − max ⁡ i = 1 k w e i + min ⁡ i = 1 k w e i \sum\limits_{i=1}^{k}{w_{e_i}} - \max\limits_{i=1}^{k}{w_{e_i}} + \min\limits_{i=1}^{k}{w_{e_i}} i=1∑k​wei​​−i=1maxk​wei​​+i=1mink​wei​​,求 1 1 1 到每個點的路徑的最小值。

我們考慮建分層圖,每層圖之間代表著它們的操作,由題意有兩種操作,則我們需建立兩個不同執行順序的分層圖。

刪邊就是把某條邊權變為 0 0 0,而加邊則是將某條邊變為兩倍邊權 2 ∗ w 2*w 2∗w。

建出來的圖如下所示,每個點表示一層圖,圖與圖之間有單向連通的關係。

CodeForces1473E 分層圖 + 最短路


最後考慮到存在路徑上只有一條邊的情況(這時候等於兩種操作都沒執行),所以我們取 m i n ( d i s [ i ] , d i s [ i + n 3 ] ) min(dis[i],dis[i+n3]) min(dis[i],dis[i+n3]) 即可。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
const int maxn = 2e5 + 5;

LL dis[maxn << 4];
int head[maxn << 4], cnt;
bool use[maxn << 4];

struct node{
    int v, w, next;
}edge[maxn << 4]; // * 16

inline void add(int u, int v, int w){
    edge[++cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
}

int main() {
    IOS;
    int n, m, u, v, w, n2, w2, n3;
    memset(dis, 0x3f, sizeof dis);
    cin >> n >> m;
    n2 = n + n;
    n3 = n2 + n;
    while(m--){
        cin >> u >> v >> w;
        w2 = w + w;
        for(int i = 1; i <= 2; i++){
            // the first graph
            add(u, v, w);
            add(u, v + n, 0);
            add(u, v + n2, w2);
            // the second graph
            add(u + n, v + n, w);
            add(u + n, v + n3, w2);
            // the third graph
            add(u + n2, v + n2, w);
            add(u + n2, v + n3, 0);
            // the fourth graph
            add(u + n3, v + n3, w);
            swap(u, v);     // undirected graph
        }
    }
    // SPFA was dead, Dijkstra yyds!!
    dis[1] = 0;
    priority_queue<pair<LL, int>, vector<pair<LL, int>>, greater<pair<LL, int>> > q;
    q.push(make_pair(0, 1));
    while (!q.empty()){
        u = q.top().second;
        q.pop();
        if(use[u]) continue;
        use[u] = true;
        for(int k = head[u]; k; k = edge[k].next){
            v = edge[k].v;
            if(dis[v] > dis[u] + edge[k].w){
                dis[v] = dis[u] + edge[k].w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
    for(int i = 2; i <= n; i++){
        // may be only exist one road
        cout << min(dis[i + n3], dis[i]) << " ";
    }
}