1 条题解

  • 0
    @ 2025-10-25 11:53:58

    「联合省选 2020 A | B」信号传递 题解

    问题分析

    这个问题要求通过重新排列 mm 个信号站的位置,最小化给定信号传递序列的总时间消耗。

    关键观察

    1. 传递方式

      • 向右传递:直接传递,代价 = 距离
      • 向左传递:通过控制塔,代价 = k×(ij+1)k \times (|i-j| + 1)
    2. 问题转化:将信号站排列问题转化为在 m!m! 种排列中寻找最优解

    3. 数据范围m23m \leq 23 提示可以使用状态压缩动态规划

    算法思路

    1. 代价预处理

    对于信号传递序列中的每一对相邻信号站 (Si,Sj)(S_i, S_j)

    • 如果 SjS_jSiS_i 右侧:代价 = 位置差
    • 如果 SjS_jSiS_i 左侧:代价 = k×(ij+1)k \times (|i-j| + 1)

    预处理出 p[a][b]p[a][b] 表示信号站 aabb相对代价系数

    2. 状态压缩DP

    定义状态:

    • f[mask]f[mask]:已放置信号站集合为 maskmask 时的最小总代价
    • now[i]now[i]:在当前已放置集合下,信号站 ii 的代价系数

    状态转移:

    $$f[mask \cup \{j\}] = \min\left(f[mask \cup \{j\}], f[mask] + now[j] \times (|mask|+1)\right) $$

    3. 代价动态更新

    关键优化:当新加入信号站 jj 时,动态更新所有未放置信号站的代价系数:

    now[k]+=p[j][k]now[k] += p[j][k]

    代码实现分析

    1. 代价系数计算

    rep(i, 1, n) {
        if (i != 1 && s[i - 1] != s[i]) {
            p[s[i - 1] - 1][s[i] - 1] += 1 - k;  // 向右传递
            now[s[i] - 1] += k;                  // 向左传递的基础代价
        }
        if (i != n && s[i + 1] != s[i]) {
            p[s[i + 1] - 1][s[i] - 1] += k + 1;  // 向左传递
            --now[s[i] - 1];                     // 调整系数
        }
    }
    

    2. 状态压缩DP

    memset(f, 0x3f, sizeof(f));
    f[0] = 0;
    rep(i, 0, N) {
        // 动态更新代价系数
        rep(j, 0, m - 1) if ((i >> j & 1) ^ (lst >> j & 1)) {
            rep(k, 0, m - 1)
                now[k] += ((i >> j & 1) - (lst >> j & 1)) * p[j][k];
        }
        
        // 状态转移
        rep(j, 0, m - 1) if (!(i >> j & 1)) {
            f[i | (1 << j)] = min(f[i | (1 << j)], 
                                f[i] + now[j] * (__builtin_popcount(i) + 1));
        }
        lst = i;
    }
    

    复杂度分析

    • 预处理O(n+m2)O(n + m^2)
    • 状态数O(2m)O(2^m)
    • 状态转移O(m2)O(m^2) 每次状态更新
    • 总复杂度O(2mm2)O(2^m \cdot m^2),对于 m23m \leq 23 可接受

    算法标签

    🏷️ 主要算法

    状态压缩动态规划 (State Compression DP)

    • 使用 bitmask 表示已放置信号站集合
    • 状态数 2m2^m,适合 m23m \leq 23

    位运算优化 (Bit Manipulation Optimization)

    • 使用 __builtin_popcount 快速计算集合大小
    • 位运算处理集合操作

    🏷️ 预处理技术

    代价系数预计算 (Cost Coefficient Precomputation)

    • 统计信号传递序列中的转移频率
    • 合并相同类型的代价计算

    动态代价更新 (Dynamic Cost Update)

    • 在状态转移过程中实时更新代价系数
    • 避免重复计算

    🏷️ 优化策略

    增量计算 (Incremental Computation)

    • 只计算状态变化带来的代价变化
    • 减少不必要的重复计算

    记忆化搜索 (Memoization)

    • 存储中间结果避免重复计算
    • 提高算法效率

    🏷️ 问题特征

    排列优化 (Permutation Optimization)

    • m!m! 种排列中寻找最优解
    • 利用对称性减少搜索空间

    图论建模 (Graph Modeling)

    • 将信号站视为图中的节点
    • 传递代价作为边的权重

    这个解决方案通过状态压缩DP动态代价更新,在 O(2mm2)O(2^m \cdot m^2) 的时间内解决了信号站排列优化问题,充分体现了位运算和动态规划在组合优化问题中的强大能力。

    • 1

    信息

    ID
    4065
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者