ABC410 D - XOR Shortest Walk
ABC410 D - XOR Shortest Walk
D - XOR Shortest Walk
问题陈述
有一个有向图,包含 $N$ 个顶点和 $M$ 条边,顶点编号为 $1$ 到 $N$,边编号为 $1$ 到 $M$。
第 $i$ 条边是从顶点 $A_i$ 到顶点 $B_i$ 的有向边,权重为 $W_i$。
请找到一条从顶点 $1$ 到顶点 $N$ 的路径,使得路径上边权重的按位异或(XOR)值最小。
约束条件
- $2 \leq N \leq 1000$
- $0 \leq M \leq 1000$
- $1 \leq A_i, B_i \leq N$
- $0 \leq W_i < 2^{10}$
所有输入值均为整数。
输入格式
1
2
3
4
5
N M
A_1 B_1 W_1
A_2 B_2 W_2
⋮
A_M B_M W_M
输出格式
- 如果不存在从顶点 $1$ 到顶点 $N$ 的路径,输出
-1。 - 如果存在,输出路径上边权重异或值的最小值。
输入输出样例
示例 1
1
2
3
4
3 3
1 2 4
2 3 5
1 3 2
1
1
路径 (边 1, 边 2) 的边权异或值是 $1$。
示例 2
1
2
3
4
5
4 4
1 4 7
4 2 2
2 3 4
3 4 1
1
0
路径 (边 1, 边 2, 边 3, 边 4) 的异或值是 $0$。
示例 3
1
2
3
4
5
999 4
1 2 9
2 1 8
1 2 7
1 1 6
1
-1
不存在从顶点 $1$ 到顶点 $999$ 的路径,输出 $-1$。
解析
很标准的一道DFS/BFS题目,不过这里因为存在一个异或,所以存在一个巧思。我们将访问过的标记数组改为二维的,这样一来,我们不会漏掉更优答案的同时避免了环。
示例代码
DFS做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
vector<PII> G[N];
int n, m, ans = inf;
bool vis[N][M];
void dfs(int u, int x)
{
if (vis[u][x]) return;
vis[u][x] = true;
if (u == n)
{
ans = min(ans, x);
}
for (auto ed : G[u]) dfs(ed.first, x ^ ed.second);
}
void solve()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v, w; cin >> u >> v >> w;
G[u].push_back({v, w});
}
dfs(1, 0);
cout << (ans == inf ? -1 : ans) << endl;
}
BFS做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
vector<PII> G[N];
int n, m;
bool vis[N][M];
queue<PII> q;
void solve()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v, w; cin >> u >> v >> w;
G[u].push_back({v, w});
}
q.push({1, 0}); vis[1][0] = 1;
while (q.size())
{
auto [u, val] = q.front(); q.pop();
for (auto [v, w] : G[u])
{
if (!vis[v][val ^ w])
{
vis[v][val ^ w] = 1;
q.push({v, val ^ w});
}
}
}
int ans = -1;
for (int i = 0; i < 1024; i++) if (vis[n][i]) {ans = i; break;};
cout << ans << endl;
}
本文由作者按照 CC BY 4.0 进行授权