Missing Number in Graph

Missing Number in Graph

一、问题概述

给定一个连通无向图,顶点数为 \(N\),边数为 \(M\)。共有 \(N+1\) 张卡片,分别写着 \(0, 1, \dots, N\)。

操作过程:

  1. 每个顶点放一张卡片,剩下的那一张被吃掉(设为 \(e\))。
  2. 每条边上写入两端顶点卡片数字的异或值 \(X_i\)。
  3. 给定图结构与边权 \(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;
}
posted @ 2026-10-26 14:19  thenrify  阅读(5)  评论(0)    收藏  举报