运用了按位异或的玄妙性质来减小建边量
eg. \((001)_2 \rightarrow (100)_2 = (001)_2 \rightarrow (000)_2 \rightarrow (100)_2\)
这样我们在额外建边时只需建 \(i \rightarrow i \ XOR \ 2^k\)
注意处理 0 号节点,因为有可能经过 0 号节点 不然会过不了样例并 AC 本题
# include <iostream>
# include <cstdio>
# include <queue>
# define MAXN 100005
# define MAXM 7000005
// # define MAXN 105
// # define MAXM 105
using namespace std;
template<typename T>
T rd(){
T fl = 1, x = 0;
int ch = getchar();
for( ;!isdigit(ch); ch = getchar()){
if(ch == ‘-‘){
fl = -1;
}
}
for( ; isdigit(ch); ch = getchar()){
x = x * 10 + ch - ‘0‘;
}
return fl * x;
}
//
struct edge{
int u, v, next, w;
}e[MAXM<<1];
int hd[MAXM<<1], cntE;
void AddE(int u, int v, int w){
e[++cntE].u = u, e[cntE].v = v, e[cntE].w = w, e[cntE].next = hd[u], hd[u] = cntE;
}
//
struct node{
int id, dis;
bool operator > (const node that) const{
return this->dis > that.dis;
}
bool operator < (const node that) const{
return this->dis < that.dis;
}
};
int dis[MAXN], vis[MAXN];
void Dij(int from, int lim){
priority_queue<node, vector<node>, greater<node> >Q;
for(int i = 0; i <= lim; i++){
dis[i] = 1<<25, vis[i] = 0;
} // 这里注意有可能会有从 0 出来的边
dis[from] = 0;
Q.push((node){from, dis[from]});
while(!Q.empty()){
node now = Q.top(); Q.pop();
if(vis[now.id]){
continue;
}
vis[now.id] = 1;
for(int i = hd[now.id]; i; i = e[i].next){
if(dis[now.id] + e[i].w < dis[e[i].v]){
dis[e[i].v] = dis[now.id] + e[i].w;
Q.push((node){e[i].v, dis[e[i].v]});
}
}
}
}
//
int main(){
int n, m, c;
n = rd<int>(), m = rd<int>(), c = rd<int>();
// // 处理加边
for(int i = 0; i <= n; i++){
for(int j = 0, to; j <= 20; j++){
to = i ^ (1<<j);
if(to <= n){
AddE(i, to, c * (1<<j));
// AddE(to, i, c * (1<<j));
}
}
} // 注意有可能会连到 0 位置,所以外层的遍历要从 0 开始
// // 处理加边
for(int i = 1, u, v, w; i <= m; i++){
u = rd<int>(), v = rd<int>(), w = rd<int>();
AddE(u, v, w);
}
int from, to;
from = rd<int>(), to = rd<int>();
Dij(from, n);
cout<<dis[to];
return 0;
}
[最短路][二进制][Code+#4] Luogu P4366 最短路
原文:https://www.cnblogs.com/Foggy-Forest/p/13402943.html