Crystal Switches
题目来源:AtCoder Beginner Contest 277 E - Crystal Switches
题目链接:E - Crystal Switches (atcoder.jp)
题意
给定一个\(N\)个点\(M\)条边的无向图。每条边 {\(u_i\ v_i\ a_i\)},表示\(u_i\)、\(v_i\)之间有一条初始状态为\(a_i\)的无向边,当\(a_i=1\),这条边初始可以使用,当\(a_i=0\),这条边初始不能使用。图上有\(K\)个点,结点处有开关,当位于这些结点处时,可以按下开关,使得图上所有边的状态翻转。
求:从点\(1\)到点\(N\)的最短路。
数据范围:\(1 \le N,M \le 2 \times 10^5\),\(0 \le K \le N\).
思路:最短路
考虑如何建图:
当图上开关总共按了偶数次时,初始状态为\(1\)的边是可以使用的;当图上开关总共按了奇数次时,初始状态为\(0\)的边是可以使用的。
于是,我们将每个点\(x\)拆成两个点:\(x\),开关按下了偶数次时的结点\(x\);\(x+N\),开关按下了奇数次时的结点\(x\)。
- 对于边 {\(u\ v\ 1\)},建出边 \(u \stackrel{1}{\longleftrightarrow} v\)
- 对于边 {\(u\ v\ 0\)},建出边 \(u+N \stackrel{1}{\longleftrightarrow} v+N\)
- 对于有开关的结点\(s_i\),则建出边 \(s_i \stackrel{0}{\longleftrightarrow} s_i+N\)
建图之后,跑一遍起点为\(1\)的最短路,则要求的最短路就是 \(min(dist[N],dist[N+N])\).
时间复杂度:\(O((M+K)·log(M+K))\).
代码
#include <bits/stdc++.h>
#define endl '\n'
#define PII pair<int,int>
using namespace std;
const int N = 400010;
const int INF = 0x3f3f3f3f;
int n, m, k, dist[N], st[N];
vector<PII> g[N];
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while(heap.size()) {
auto t = heap.top();
heap.pop();
int u = t.second;
if(st[u]) continue;
st[u] = true;
for(auto item : g[u]) {
int v = item.first, w = item.second;
if(dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
heap.push({dist[v], v});
}
}
}
int res = min(dist[n], dist[n + n]);
return res == INF ? -1 : res;
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin >> n >> m >> k;
for(int i = 1; i <= m; ++ i) {
int x, y, a;
cin >> x >> y >> a;
if(a) g[x].push_back({y, 1}), g[y].push_back({x, 1});
else g[x + n].push_back({y + n, 1}), g[y + n].push_back({x + n, 1});
}
for(int i = 1; i <= k; ++ i) {
int x;
cin >> x;
g[x].push_back({x + n, 0}), g[x + n].push_back({x, 0});
}
cout << dijkstra() << endl;
return 0;
}
标签:AtCoder,dist,Beginner,int,短路,back,heap,277,push
From: https://www.cnblogs.com/jakon/p/16888643.html