高维子集和&子集染色问题

先给出待解决的问题,如下:

问题描述

给定正整数 nnn,考虑集合 U={0,1,...,n−1}U = \{0,1,\dots,n-1\}U={0,1,...,n−1} 的所有 2n2^n2n 个子集。每个子集 SSS 可以染成红色或蓝色,分别有代价 red[S]red[S]red[S] 和 blue[S]blue[S]blue[S]。染色方案需要满足:若两个子集 S1S_1S1 和 S2S_2S2 颜色相同,则它们的并集 S1∪S2S_1 \cup S_2S1∪S2 也必须染成相同的颜色。求所有子集染色代价的最小和。

解题报告

我们定义最终选择为红色的集合是 RRR,选择为蓝色的集合是 BBB,需要满足条件有 R+B=UR + B = UR+B=U。

并且,我们希望在满足限制条件的情况下,最小化 ∑S⊆Bblue[S]+∑S⊆Rred[S]\sum^{}{S \subseteq B} blue[S] + \sum^{}{S \subseteq R} red[S]∑S⊆Bblue[S]+∑S⊆Rred[S]。

根据 R+B=UR + B = UR+B=U,我们可以将上式转为 ∑S⊆Ublue[S]+∑S⊆Rred[S]−blue[S]\sum_{S \subseteq U} blue[S] + \sum_{S \subseteq R} red[S] - blue[S]∑S⊆Ublue[S]+∑S⊆Rred[S]−blue[S]。

则,定义 diff[S]=red[S]−blue[S]diff[S] = red[S] - blue[S]diff[S]=red[S]−blue[S]。

即求,
min⁡(∑S⊆Rdiff[S]) \min (\sum_{S \subseteq R} diff[S]) min(S⊆R∑diff[S])

在这个式子中,我们唯一的未知量就是这个 RRR 集合。接着,给出对于 RRR 集合的限制条件如下,
S1⊆R,S2⊆R,S1∪S2⊆R S1 \subseteq R,S2\subseteq R,S1 \cup S2 \subseteq R S1⊆R,S2⊆R,S1∪S2⊆R

对于这个式子,需要对 BBB 和 RRR 集合均满足该限制条件。

存在性引理与证明

引理 :对于任意非空集合 S⊆US \subseteq US⊆U,若 SSS 是红色的,则存在元素 x∈Sx \in Sx∈S,使得所有包含 xxx 的 SSS 的子集都是红色的。类似地,若 SSS 是蓝色的,则存在元素 x∈Sx \in Sx∈S,使得所有包含 xxx 的 SSS 的子集都是蓝色的。

证明 (以红色为例):假设 SSS 是红色的,但不存在这样的 xxx。则对每个 x∈Sx \in Sx∈S,都存在一个包含 xxx 的蓝色子集 Tx⊆ST_x \subseteq STx⊆S。考虑所有蓝色子集的并集 T=⋃x∈STxT = \bigcup_{x \in S} T_xT=⋃x∈STx,由于每个 xxx 都属于某个 TxT_xTx,故 T=ST = ST=S。又蓝色子集族对并封闭,因此 SSS 必须是蓝色的,矛盾。

该引理表明,对于任何非空集合 SSS,染色方案的结构可由某个关键元素 xxx 决定:所有包含 xxx 的子集颜色相同,且该颜色决定了 SSS 本身的颜色。

当然,特殊的是"空集",由于空集在本题中为 000,所以不影响任何一个阵营,所以,可以将 blue[0]blue[0]blue[0]、red[0]red[0]red[0] 选择其一即可,即 min⁡(0,diff[0])\min (0, diff[0])min(0,diff[0])。证明如下。

空集的独立性 :空集 ∅\emptyset∅ 与任何子集的并都是那个子集,因此空集的颜色选择不影响其他子集之间的封闭性。空集染红色的额外代价为 diff[∅]diff[\emptyset]diff[∅],染蓝色的额外代价为 000。故空集的最优选择是取 min⁡(diff[∅],0)\min(diff[\emptyset], 0)min(diff[∅],0),我们可以将其单独处理。

得到动态规划模型 :不妨钦定 dp[S]dp[S]dp[S] 表示 SSS 集合内的所有子集都已经确定了从属关系的最优解(最小化代价),当然,这里的代价是 diff[S]diff[S]diff[S] 最小化。

其中,我们需要维护的状态是这样的,确定 SSS 从属于哪个阵营 RRR、BBB。并且,如果它从属于这个阵营,那么它必须得有至少一个这样的 xxx,使得包含这个 xxx 的全部都在这个阵营里。

那么,得到形如这样的状态转移方程:
dp[S]=min⁡(dp[S′]+min(0,sum[S]−sum[S′])) dp[S] = \min(dp[S'] + min(0, sum[S] - sum[S'])) dp[S]=min(dp[S′]+min(0,sum[S]−sum[S′]))

在这里 sum[S]sum[S]sum[S] 表示 SSS 的所有子集之和。

于是,考虑求解子集的子集和问题,朴素做法是 O(3n)O(3^n)O(3n) 的。但是可以使用高维子集和进行优化。

举个例子,我们对于二进制 1011,看作四维坐标(1,0,1,1),于是用多维前缀和的做法可以优化到 O(n2n)O(n 2^n)O(n2n)。

求解过程与代码如下:
sum[S]+=sum[S⊗2i],2i&S=2i sum[S] += sum[S \otimes 2^i], 2^i \&S = 2^i sum[S]+=sum[S⊗2i],2i&S=2i

cpp 复制代码
    for(int i = 0; i < n; i ++) {
        for(int sta = 1; sta < up; sta ++) {
            if((sta >> i) & 1) sum[sta] += sum[sta ^ (1 << i)];
        }
    }

模拟多维前缀和,代码如上。

需要注意的是,一开始 sum[sta]=diff[sta]sum[sta] = diff[sta]sum[sta]=diff[sta]。

在本题中,由于 diff[]diff[]diff[] 数组没有别的用了,节约内存,可以直接用 diff[]diff[]diff[] 来代替 sum[]sum[]sum[] 了。

代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (1 << 20) + 1;
void read(int &x) {
    x = 0;
    char ch = getchar();
    int op = 1;
    while(!isdigit(ch)) {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    x = x * op;
}
#define inf 0x3f3f3f3f3f3f3f3f
int n, up, a[maxn], b[maxn];
ll diff[maxn], dp[maxn];
int main() {
    read(n);
    up = 1 << n;
    ll all = 0;
    for(int i = 0; i < up; i ++) read(a[i]);
    for(int i = 0; i < up; i ++) {
        read(b[i]);
        all += b[i];
        diff[i] = a[i] - b[i];
    }
    for(int i = 0; i < n; i ++) {
        for(int sta = 1; sta < up; sta ++) {
            if((sta >> i) & 1) diff[sta] += diff[sta ^ (1 << i)];
        }
    }
    for(int sta = 1; sta < up; sta ++) {
        dp[sta] = inf;
        for(int i = 0; i < n; i ++) {
            if((sta >> i) & 1) {
                dp[sta] = min(dp[sta], dp[sta ^ (1 << i)] + min(0LL, diff[sta] - diff[sta ^ (1 << i)]));
            }
        }
    }
    printf("%lld\n", dp[up - 1] + all + min(0LL, diff[0]));
    return 0;
}
/*
3
2 -3 1 -1 2 3 2 -2
-1 -2 2 3 -1 2 -1 2
ans:-5
3
1 1 1 1 1 1 1 1
2 2 2 -3 0 2 2 2
ans:5
*/
相关推荐
Tisfy2 小时前
LeetCode 3651.带传送的最小路径成本:动态规划
算法·leetcode·动态规划·题解·排序
王老师青少年编程5 小时前
信奥赛C++提高组csp-s之数位DP详细讲解
c++·动态规划·csp·数位dp·信奥赛·csp-s·提高组
王老师青少年编程5 小时前
信奥赛C++提高组csp-s之状压DP详解及编程实例
c++·动态规划·csp·状压dp·信奥赛·csp-s·提高组
不知名XL21 小时前
day35 动态规划 part08
算法·动态规划
.格子衫.1 天前
029动态规划之划分型DP——算法备赛
算法·动态规划
Snow_day.1 天前
【补题记录】AT441,442
数据结构·算法·贪心算法·动态规划·图论
悠哉悠哉愿意1 天前
【科研学习记录】自适应动态规划(ADP)与强化学习(RL)理论入门
学习·算法·动态规划·adp·自适应动态规划
王老师青少年编程1 天前
信奥赛C++提高组csp-s之树形DP详解及编程实例
c++·动态规划·树形dp·csp·信奥赛·csp-s·提高组
知星小度S2 天前
动态规划(一)——思想入门
算法·动态规划