AtCoder Beginner Contest 277 E // 最短路

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;
}
posted @ 2022-11-14 12:14  Jakon  阅读(120)  评论(0编辑  收藏  举报