XOR最短路径 BFS
解题思路分析:
-
问题理解:
-
需要在有向图中找到从1到N的任意行走(允许重复访问节点和边)
-
目标是使路径上所有边权重的异或值最小
-
-
关键观察:
-
异或操作的性质:a ^ b ^ b = a(走两次同一条边会抵消)
-
因此可以允许路径中出现"来回走"的情况来调整异或值
-
-
算法选择:
-
使用BFS遍历所有可能的异或值
-
维护vis[x][k]数组记录到达节点x时异或值为k的可能性
-
由于边权<2^10,异或值最多2047种可能,空间可以接受
-
-
复杂度分析:
-
时间复杂度:O(N*2048) ≈ 2e6,可以接受
-
空间复杂度:O(N*2048) ≈ 8e6,可以接受
-
-
算法正确性:
-
BFS保证了我们能探索所有可能的路径组合
-
通过维护异或值而不是路径长度,可以找到最优解
-
最后遍历所有可能的异或值找到最小值
-
-
边界处理:
-
无解时输出-1
-
正确处理自环边和重边的情况
-
-
优化点:
-
可以提前终止搜索,当找到异或值为0时直接返回
-
可以使用位运算优化异或计算
-
#include<bits/stdc++.h> #define pii pair<int,int> using namespace std; // 常量定义 const int N = 2e3 + 10; // 最大顶点数的两倍 const int inf = 0x3f3f3f3f; // 无穷大值 vector<pii> g[N]; // 邻接表存储图,g[x]存储从x出发的边(pair<终点,权重>) int vis[N][N]; // vis[x][k]标记是否可以通过某路径到达x点且异或值为k int n, m; // 顶点数和边数 // BFS广度优先搜索函数 void bfs(int s) { queue<pii> q; // 队列存储待处理的节点和当前异或值 vis[s][0] = 1; // 起点s的初始异或值为0 q.push({s, 0}); // 将起点加入队列 while(q.size()) { int x = q.front().first; // 当前节点 int k = q.front().second; // 当前路径的异或值 q.pop(); // 遍历当前节点的所有邻接边 for(int i = 0; i < g[x].size(); i++) { int y = g[x][i].first; // 邻接节点 int z = g[x][i].second; // 边权重 int w = k ^ z; // 新的异或值 // 如果这个状态(y,w)未被访问过 if(!vis[y][w]){ vis[y][w] = 1; // 标记为已访问 q.push({y, w}); // 加入队列继续处理 } } } } int main() { cin >> n >> m; // 输入顶点数和边数 // 构建邻接表 for(int i = 1; i <= m; i++) { int x, y, z; cin >> x >> y >> z; g[x].push_back({y, z}); // 添加有向边 } bfs(1); // 从顶点1开始BFS int ans = inf; // 遍历所有可能的异或值(0到2047) for(int i = 0; i <= (2 << 10); i++) if(vis[n][i]) // 如果存在到n点且异或值为i的路径 ans = min(ans, i); // 更新最小值 if(ans == inf) cout << -1; // 无解情况 else cout << ans; // 输出最小异或值 return 0; }

浙公网安备 33010602011771号