(图)最小瓶颈路

0 阅读3分钟

一、题意梳理

链接:ac.nowcoder.com/acm/contest…
来源:牛客网

  1. 图规模极大,任意两点 u,v 直接连边,边权 w(u,v)=u⊕v;
  2. 路径权值定义:路径上所有边权的最大值(路径瓶颈);
  3. 目标:找到 l→r 的路径,使路径瓶颈尽可能小,并输出路径节点序列;
  4. 输出限制:节点数量 n≤2×105,节点互不重复。

二、基础前置知识

1. 异或恒等式

对任意三个数 a,b,c:(a⊕b)⊕(b⊕c)=a⊕c

2. 最高位定义

设 X=l⊕r,mask 代表 X 的二进制最高位权值(2 的幂)。性质:l 和 r 在 mask 这一位二进制值一个为 0、一个为 1;高于 mask 的所有二进制位,l 和 r 完全相同。

三、核心结论 1:所有路径瓶颈的理论下界为 mask

任意一条 l 到 r 的路径,瓶颈一定 ≥mask。

证明

随便拆分路径为两段:l→mid→r,记:A=l⊕mid, B=mid⊕r由异或恒等式:A⊕B=l⊕r=X。X 的最高位是 mask,说明 A,B 在 mask 位一个 0、一个 1;二进制该位为 1 的数字一定 ≥mask,因此 max(A,B)≥mask。即:任何路径的瓶颈不可能比 mask 更小,mask 是全局最优下界。

四、核心结论 2:一定存在路径瓶颈恰好等于 mask(分两种情况)

情况 1:X=mask(l⊕r 本身是 2 的幂)

此时直接走两点路径 l→r:唯一边权 l⊕r=mask,瓶颈恰好等于下界,是最优解。⚠️ 若强行构造三段路径:mid=l⊕mask=r,会出现重复节点 r,路径非法,必须直接输出两点。

情况 2:X>mask(l⊕r 包含多个二进制 1)

构造三段路径:l→mid→r,其中 mid=l⊕mask。

构造合理性证明

  1. l⊕mid=l⊕(l⊕mask)=mask,第一条边权等于 mask;
  2. l 与 r 在 mask 位相反,mid 与 l 在 mask 位相反 → mid 与 r 在 mask 位相同;两个数字最高位相同,异或结果最高位一定小于 mask,即 mid⊕r<mask;
  3. 整条路径瓶颈:max(mask, <mask)=mask,达到理论最优;
  4. mid=l⊕mask=l,且 mid=r,无重复节点,合法。

补充:为什么不用 mid=l&(∼mask)

mid=l&(∼mask) 作用是把 l 的 mask 位清零,存在致命漏洞:若 l 在 mask 位原本就是 0,l&(∼mask)=l,路径出现重复节点 l,非法。而 mid=l⊕mask 是翻转 mask 位,无论原 bit 是 0/1,都能得到和 l 不同的中间点,全覆盖所有场景。

五、完整解题算法步骤

输入 l,r

  1. 计算 X=l⊕r;

  2. 求出 X 的最高位权值 mask;

  3. 分支判断:

    • 若 X==mask:输出 2 个节点 l r;
    • 若 X>mask:计算 mid=l⊕mask,输出 3 个节点 l mid r;
  4. 输出节点数量,再输出节点序列。

六、边界样例验证

样例 1:l=4, r=6

X=4⊕6=2, mask=2,满足 X=mask

七、完整 AC 代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long

// 获取数字x的二进制最高位权值
ll getHigh(ll x){
    ll mask = 1;
    while((mask << 1) <= x){
        mask <<= 1;
    }
    return mask;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll l, r;
    cin >> l >> r;
    ll xor_lr = l ^ r;
    ll mask = getHigh(xor_lr);
    
    if(xor_lr == mask){
        // 仅最高位不同,直连两点最优
        cout << "2\n";
        cout << l << " " << r << "\n";
    }else{
        // 构造三段无重复路径
        ll mid = l ^ mask;
        cout << "3\n";
        cout << l << " " << mid << " " << r << "\n";
    }
    return 0;
}