CodeForces1473E 分層圖 + 最短路
阿新 • • 發佈:2021-02-18
技術標籤:題解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∑kwei−i=1maxkwei+i=1minkwei,求 1 1 1 到每個點的路徑的最小值。
我們考慮建分層圖,每層圖之間代表著它們的操作,由題意有兩種操作,則我們需建立兩個不同執行順序的分層圖。
刪邊就是把某條邊權變為 0 0 0,而加邊則是將某條邊變為兩倍邊權 2 ∗ w 2*w 2∗w。
建出來的圖如下所示,每個點表示一層圖,圖與圖之間有單向連通的關係。
最後考慮到存在路徑上只有一條邊的情況(這時候等於兩種操作都沒執行),所以我們取
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]) << " ";
}
}