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=1kweii=1maxkwei+i=1minkwei,求 1 1 1 到每個點的路徑的最小值。

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

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

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

分層圖
最後考慮到存在路徑上只有一條邊的情況(這時候等於兩種操作都沒執行),所以我們取 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]) << " "; } }