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;
}