P4366 [Code+#4]最短路 建图 最短路

P4366 [Code+#4]最短路

题目链接

​ 建图,最短路。

(n ^ 2 + m)条边肯定是不允许的。那(m)条边肯定是要建的,考虑(n ^ 2)那些边怎么建比较好。

​ 我们发现有一些边是没有用的,举个例子。

如果我们要从1走到4
1 ^ 4 = 5, 总路程为5c
1 ^ 0 = 1, 0 ^ 4 = 4, 总路程为5c

​ 也就是说,有一些边可以被另一些边代替,那么具体一点就是:

​ 只需要对(i, i + 2 ^ 0, i + 2 ^ 1, i + 2 ^ 2……)这些点连边就好了。

​ 那么现在就只有(nlongn +m)条边了,然后就可以愉快的dij了。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5, M = 5e6 + 5;
const long long inf = 1e18;
int n, m, c, s, t, cnt;
int vis[N], head[N];
long long dis[N];
struct edge { int to, nxt, val; } e[M];

void add(int x, int y, int z) {
    e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z;
}

void run_dij() {
    priority_queue <pair<long long, int>, vector<pair<long long, int> >, greater<pair<long long, int> > > q;
    for(int i = 0;i <= n; i++) dis[i] = inf; 
    dis[s] = 0; q.push(make_pair(dis[s], s));
    while(!q.empty()) {
        int x = q.top().second; q.pop();
        if(vis[x]) continue; vis[x] = 1;
        if(x == t) break; //一个优化,不然会T几个点
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; 
            if(dis[y] > dis[x] + e[i].val) 
                dis[y] = dis[x] + e[i].val, q.push(make_pair(dis[y], y));
        }
    }
}

int main() {

    n = read(); m = read(); c = read();
    for(int i = 1, x, y, z;i <= m; i++) x = read(), y = read(), z = read(), add(x, y, z);
    for(int i = 0;i <= n; i++) //注意0也要加边
        for(int j = 0;(1 << j) <= n; j++) {
            if((i ^ (1 << j)) > n) continue;
            int tmp = i ^ (1 << j); add(i, tmp, (1 << j) * c);
        } 
    s = read(); t = read();
    run_dij(); printf("%lld", dis[t]);

    return 0;
}
原文地址:https://www.cnblogs.com/czhui666/p/13789169.html