Missing Number in Graph
Missing Number in Graph
一、问题概述
给定一个连通无向图,顶点数为 \(N\),边数为 \(M\)。共有 \(N+1\) 张卡片,分别写着 \(0, 1, \dots, N\)。
操作过程:
- 每个顶点放一张卡片,剩下的那一张被吃掉(设为 \(e\))。
- 每条边上写入两端顶点卡片数字的异或值 \(X_i\)。
- 给定图结构与边权 \(X_i\),求被吃掉的卡片数字 \(e\)。若无法唯一确定,输出
-1。
二、核心数学推导
1. 引入变量
- 设 顶点 \(v\) 上的真实卡片数字 为 \(c_v\)。
- 设 被吃掉的卡片数字 为 \(e\)。
- 设 顶点 1 上的数字 为 \(x\),即 \(c_1 = x\)。
2. 引入“相对值” \(a_v\)
我们不知道 \(x\),但可以构建一个辅助数组 \(a_v\),使得:
\[c_v = x \oplus a_v
\]
并且令基准点:
\[a_1 = 0
\]
为什么可以这么做?
对于任意边 \((u, v)\),其边权为:
\[X = c_u \oplus c_v = (x \oplus a_u) \oplus (x \oplus a_v) = a_u \oplus a_v
\]
我们发现,未知数 \(x\) 被完全消掉了!
因此,我们只需要从顶点 1 出发 BFS,利用公式:
\[a_v = a_u \oplus X
\]
就可以唯一确定所有顶点的 \(a_v\) 值,与真实的 \(x\) 无关。
三、利用全局异或等式
所有卡片数字的集合是 \(\{0, 1, \dots, N\}\),而顶点上的数字集合是 \(\{c_1, \dots, c_N\}\),缺失的就是 \(e\)。因此有恒等式:
\[\left(\bigoplus_{i=0}^{N} i\right) \oplus e = \bigoplus_{v=1}^{N} c_v
\]
其中 \(\oplus\) 表示按位异或运算。
将 \(c_v = x \oplus a_v\) 代入右边:
\[\bigoplus_{v=1}^{N} c_v = \bigoplus_{v=1}^{N} (x \oplus a_v)
\]
此时根据 \(N\) 的奇偶性,\(x\) 是否会被抵消,决定了答案能否唯一确定。
四、分类讨论
情况 1:\(N\) 为偶数
由于有偶数个顶点,\(x\) 在异或和中出现了偶数次,偶数个相同的数异或结果为 \(0\)。
所以:
\[\bigoplus_{v=1}^{N} c_v = \bigoplus_{v=1}^{N} a_v
\]
代入全局异或等式:
\[e = \left(\bigoplus_{i=0}^{N} i\right) \oplus \left(\bigoplus_{v=1}^{N} a_v\right)
\]
结论:答案被唯一确定,直接套公式计算即可。
情况 2:\(N\) 为奇数
此时 \(x\) 出现奇数次,无法消去:
\[\bigoplus_{v=1}^{N} c_v = \left(\bigoplus_{v=1}^{N} a_v\right) \oplus x
\]
因此:
\[e = \text{常数} \oplus x
\]
如果有一组合法方案,将所有顶点卡片数字同时异或 \(1\)(即 \(c'_v = c_v \oplus 1\)):
- 边权不变:\(c'_u \oplus c'_v = (c_u \oplus 1) \oplus (c_v \oplus 1) = c_u \oplus c_v\)
- 数字集合仍是 \(0 \dots N\)(因为 \(N\) 为奇数,集合在异或 \(1\) 下封闭,如 \(0 \leftrightarrow 1, 2 \leftrightarrow 3, \dots\))
此时新方案的被吃数字变为 \(e' = e \oplus 1 \neq e\),存在两个不同答案。
结论:答案无法唯一确定,直接输出 -1。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n, m; cin >> n >> m;
vector<vector<pair<int, int>>> grid(n + 1);
for(int i = 0; i < m; i ++) {
int a, b, x; cin >> a >> b >> x;
grid[a].emplace_back(b, x);
grid[b].emplace_back(a, x);
}
if(n & 1) {cout << -1 << "\n"; return;}
vector<int> a(n + 1), vis(n + 1, 0); a[1] = 0; vis[1] = 1;
queue<int> q; q.push(1);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto& e : grid[u]) {
int v = e.first, w = e.second;
if(vis[v]) continue;
a[v] = a[u] ^ w;
vis[v] = 1;
q.push(v);
}
}
int tol = 0;
for(int i = 1; i <= n; i ++) {
tol ^= i; tol ^= a[i];
}
cout << tol << "\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int t = 1; cin >> t;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号