P4366 [Code+#4]最短路
首先,可以证明,不存在一种最短路算法的时间复杂度与边数无关
其次,我们发现,这里的代价是与异或有关的,
异或可以被认为是将不同的二进制位变为相同,所以我们可以发现,两个点直接连边的代价就是将两个点变为一样的代价
举个例子
这张图片中,我们发现,异或中,若两个二进制位相同,我们不需要支付代价
这里我们就有了一个想法,我们将每一位改变的代价分别算出来,就能将一个数转移到另一个数上去
就像这样,我们可以通过对原数每一位的变动,使其到达另一个数上,从而实现转移
于是就可以愉快的敲代码了
注意一下,这里的节点数上界是n*2
,数组要开两倍
用的是 zkw 线段树优化的 Dijkstra
#include <vector>
#define pii pair<int,int>
#include <stdio.h>
#include <bitset>
#include <string.h>
using namespace std;
const int maxN=2*1e5+10;
const int inf=0x7ffffff;
int N=1,n,m,c,s,t,dis[maxN];
vector<pii> g[maxN];
bitset<maxN> vis;
struct node {
int minx[maxN<<2],mind[maxN<<2];
void pushup(int x){
mind[x]=(minx[x<<1]<minx[(x<<1)|1])?mind[x<<1]:mind[(x<<1)|1];
minx[x]=min(minx[x<<1],minx[(x<<1)|1]);
}
void build(){
for(int i=0;i<n;++i) mind[i+N]=i+N,minx[i+N]=inf;
for(int i=N-1;i>=1;--i) pushup(i);
}
void add(int x,int v){
minx[x+N-1]=v;
for(int i=(N+x-1)>>1;i;i>>=1) pushup(i);
}
int mid(){
return mind[1]-N+1;
}
}tree;
void dijkstra(){
tree.build();
tree.add(s,0);
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
while(tree.minx[1]!=inf){
int temp=tree.mid();
tree.add(temp,inf);
if(vis[temp]) continue ;
vis[temp]=1;
for(pii x:g[temp]){
if(dis[x.first]>dis[temp]+x.second){
dis[x.first]=dis[temp]+x.second;
tree.add(x.first,dis[x.first]);
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&c);
int x,y,z;
for(int i=1;i<=m;++i)
scanf("%d%d%d",&x,&y,&z),g[x].push_back({y,z});
scanf("%d%d",&s,&t);
for(int i=0;i<=n*2;++i){
//这里用2^k来异或一个数,本质上就是对这个数的二进制的某一位进行 添1/去1 的操作
//异或的过程实际上可以被认为是将两个二进制数变为一样
//毕竟在异或中,只有两个位不同,才会有贡献
//这里易得,添1和去1的操作,代价都是(1<<位数)
for(int k=1;k<=n;k<<=1){
//if((i^k)>n) continue ;
///cout << k << " " << endl;
g[i].push_back({i^k,k*c});
}
}
n*=2;
for(; N <= n+1; N <<= 1);
N>>=1;
dijkstra();
printf("%d",dis[t]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话