2026/5/13 19:43:01
网站建设
项目流程
网站单页做301,下载学校网站模板,wordpress get_most_viewed,wordpress自定义分类模板信奥赛C提高组csp-s之状压DP详解及编程实例 一、状态压缩DP的核心思想
状态压缩动态规划#xff08;简称状压DP#xff09;是一种利用二进制位运算压缩状态空间的动态规划方法。适用于状态维度较高但每个维度状态数较少的场景#xff08;如每个位置只有选/不选…信奥赛C提高组csp-s之状压DP详解及编程实例一、状态压缩DP的核心思想状态压缩动态规划简称状压DP是一种利用二进制位运算压缩状态空间的动态规划方法。适用于状态维度较高但每个维度状态数较少的场景如每个位置只有选/不选两种状态。二、核心知识点状态表示用整数的二进制位表示状态例如mask0b101表示第1、3个位置被选中常用位运算(s(k-1))1// 检查第k位是否为1s|(1(k-1))// 设置第k位为1s~(1(k-1))// 设置第k位为0s1s2// 检测状态冲突__builtin_popcount(s)// 统计1的个数GCC状态设计dp[i][mask]通常表示前i行/位置且当前状态为mask时的最优解在算法竞赛中位运算的巧妙使用可以极大提升代码效率和简洁性。以下是一些实用的小技巧和原理说明基础但关键的技巧判断奇偶性if(n1)// 等价于 n % 2 1原理二进制最低位为1时是奇数交换两个数a^b;b^a;a^b;// 无需临时变量原理利用异或的自反性a ^ a 0取相反数intnegative~n1;// 等价于 -n原理二进制补码表示法进阶状态处理技巧快速获取最低位的1intlowbitx(-x);// 示例0b10100 - 0b100应用树状数组核心操作遍历所有子集for(intsubsets;subset;subset(subset-1)s){// 处理subset}示例s0b101时遍历顺序 0b101→0b100→0b001统计二进制中1的个数intcount__builtin_popcount(n);// GCC内置函数intcountbitset32(n).count();// C标准库状压DP中的黑科技快速判断相邻位冲突if(s(s1))// 检测是否有相邻的1应用棋盘类问题如互不侵犯枚举合法状态转移// 筛选有效状态示例vectorintvalid;for(ints0;s(1n);s){if(s(s1))continue;// 排除相邻1valid.push_back(s);}快速状态合法性验证// 检查状态s是否与掩码mask匹配boolvalid(s|mask)mask;性能对比表操作常规方法位运算方法加速比判断奇偶n%2 1n13x统计1的个数循环统计__builtin_popcount10x子集遍历递归生成位运算递减5x相邻冲突检测逐位比较位移与位与8x三、经典模型与例题分析1洛谷P1879 [USACO06NOV]Corn Fields G难度普及/提高代码实现#includebits/stdc.husingnamespacestd;constintMOD1e8;intm,n;intfield[15];// 存储每行的土地状态二进制压缩intdp[15][112];// dp[i][s] 表示第i行状态为s时的方案数intmain(){cinmn;for(inti1;im;i){intstate0;for(intj0;jn;j){intx;cinx;state(state1)|x;// 将土地状态压缩为二进制}field[i]state;}dp[0][0]1;// 初始化for(inti1;im;i){for(ints0;s(1n);s){if((sfield[i])!s)continue;// 状态s必须全部在肥沃格子上if(s(s1))continue;// 状态s自身不能有相邻的1for(intprev0;prev(1n);prev){if((sprev)0){// 上下两行状态不冲突dp[i][s](dp[i][s]dp[i-1][prev])%MOD;}}}}intans0;for(ints0;s(1n);s)ans(ansdp[m][s])%MOD;coutans;return0;}功能模块分解1.输入处理与状态压缩功能将每行的土地状态0/1转换为二进制整数。代码片段for(inti1;im;i){intstate0;for(intj0;jn;j){intx;cinx;state(state1)|x;}field[i]state;}说明将每行的输入例如1 0 1压缩为二进制整数如0b101即十进制5。field[i]表示第i行的合法土地掩码。2.动态规划初始化功能初始化虚拟的第0行状态。代码片段dp[0][0]1;说明第0行是虚拟行表示没有放置奶牛此时方案数为1空状态。3.状态转移功能逐行枚举所有可能的状态并检查合法性。代码片段for(ints0;s(1n);s){if((sfield[i])!s)continue;// 必须全部在肥沃格子上if(s(s1))continue;// 同一行不能有相邻的1for(intprev0;prev(1n);prev){if((sprev)0){// 上下两行不能有相邻的1dp[i][s]dp[i-1][prev];}}}关键检查条件土地合法性状态s的二进制位必须全为肥沃土地即s是field[i]的子集。行内无冲突状态s的二进制位不能有相邻的1通过s (s 1)检测。行间无冲突当前行状态s与上一行状态prev不能有上下相邻的1通过s prev 0检测。4.结果汇总功能统计最后一行的所有合法状态的总方案数。代码片段intans0;for(ints0;s(1n);s)ans(ansdp[m][s])%MOD;说明将所有可能的最终状态累加得到总方案数。关键算法分析状态压缩每行的状态用二进制数表示例如0b101表示第1、3列放置奶牛。状态总数最多为 ( 212 ^{12}12 4096 )适合动态规划。合法性检查行内检查通过s (s 1)快速判断是否有相邻的1。土地适配检查通过(s field[i]) s确保所有放置位置都是肥沃土地。示例验证假设输入为2 3 1 1 1 1 1 1可能的合法状态第1行0b000空、0b001、0b010、0b100、0b101。第2行需与第1行状态不冲突。最终总方案数为 17。四、经典模型与例题分析2洛谷P1896 [SCOI2005]互不侵犯难度普及/提高问题描述在N×N的棋盘放置K个国王要求任意两个国王不互相攻击。代码实现#includebits/stdc.husingnamespacestd;typedeflonglongll;ll dp[10][1024][90];// dp[i][mask][cnt]intn,k;vectorintvalid_states;// 检查单行合法性boolcheck(ints){return!(s(s1))!(s(s1));}// 生成所有合法行状态voidpreprocess(){for(ints0;s(1n);s){if(check(s))valid_states.push_back(s);}}intmain(){cinnk;preprocess();// 初始化第一行for(autos:valid_states){intcnt__builtin_popcount(s);if(cntk)dp[0][s][cnt]1;}// 状态转移for(inti1;in;i){for(autocur:valid_states){intcnt_cur__builtin_popcount(cur);for(intprev:valid_states){if((curprev)||(cur(prev1))||(cur(prev1)))continue;for(intc0;ck-cnt_cur;c){dp[i][cur][ccnt_cur]dp[i-1][prev][c];}}}}// 统计答案ll ans0;for(autos:valid_states)ansdp[n-1][s][k];coutans;return0;}功能模块详解1. 数据结构定义dp[10][1024][90]三维动态规划数组维度含义第一维处理到第i行棋盘共n行i ∈ [0, n-1]第二维当前行的状态压缩值mask最大状态数为2^9 512但合法状态更少第三维已放置的国王总数cnt最多k个值表示当前状态下的合法方案数。valid_states存储所有单行合法的状态二进制无相邻1。2. 预处理合法状态check(int s)检查单行状态s是否合法!(s(s1))!(s(s1)若s的二进制位有相邻的1如0b110则返回false。preprocess()遍历所有可能的单行状态s ∈ [0, 1n)筛选出合法状态存入valid_states。3. 初始化第一行for(autos:valid_states){intcnt__builtin_popcount(s);if(cntk)dp[0][s][cnt]1;}对每个合法状态s计算其包含的国王数量cnt即二进制中1的个数。若cnt ≤ k则在第一行放置该状态的方案数为1。4. 状态转移for(inti1;in;i){for(autocur:valid_states){// 当前行状态intcnt_cur__builtin_popcount(cur);for(intprev:valid_states){// 前一行状态// 检查纵向和斜向冲突if((curprev)||(cur(prev1))||(cur(prev1)))continue;// 遍历可能的国王数量for(intc0;ck-cnt_cur;c){dp[i][cur][ccnt_cur]dp[i-1][prev][c];}}}}冲突检测cur prev检查上下相邻列是否有冲突。cur (prev 1)检查当前行与上一行左移一位后的斜向冲突。cur (prev 1)检查当前行与上一行右移一位后的斜向冲突。状态转移若状态无冲突则将前一行prev状态下已放置c个国王的方案数累加到当前行cur的c cnt_cur位置。5. 结果统计ll ans0;for(autos:valid_states)ansdp[n-1][s][k];coutans;遍历最后一行的所有合法状态s累加已放置k个国王的方案数。关键设计思想状态压缩将每行的状态用二进制数表示1表示放置国王将指数级的状态空间压缩到多项式级别。合法状态筛选预处理所有单行合法状态减少无效状态转移。三维状态设计dp[i][mask][cnt]精确记录行数、当前行状态、总国王数三个维度确保转移无遗漏。复杂度分析时间复杂度( O(n⋅ S 2 ⋅ k \cdot S^2 \cdot k⋅S2⋅k) )其中 ( S ) 为合法状态数约60。当 ( n9, S≈60, k81 ) 时计算量约为 (9 ⋅ 60 2 ⋅ 81 ≈ 2.6 × 10 6 9 \cdot 60^2 \cdot 81 ≈ 2.6 \times 10^69⋅602⋅81≈2.6×106)完全可接受。空间复杂度( O(n⋅ S ⋅ k \cdot S \cdot k⋅S⋅k) )当 ( n9, S60, k81 ) 时占用约 ( 9⋅ 60 ⋅ 81 ⋅ \cdot 60 \cdot 81 \cdot⋅60⋅81⋅8B ≈ 349KB )。优化思考滚动数组优化由于当前行只依赖前一行可将dp数组压缩为二维dp[2][S][k]将空间复杂度降至 ( O(S⋅ k \cdot k⋅k) )。剪枝优化在状态转移时若c cnt_cur k可直接跳过减少无效计算。五、洛谷OJ练习题单P1896 [SCOI2005]互不侵犯基础状压DPP1879 [USACO06NOV]Corn Fields G状态合法性处理P2704 [NOI2001]炮兵阵地三维状态设计P2622 关灯问题II状态转移与位运算P3092 [USACO13NOV]No Change G状态压缩前缀和P2157 [SDOI2009]学校食堂复杂状态设计P1433 吃奶酪经典TSP问题P4011 孤岛营救问题分层图状压更多系列知识请查看专栏《信奥赛C提高组csp-s知识详解及案例实践》https://blog.csdn.net/weixin_66461496/category_13113932.html各种学习资料助力大家一站式学习和提升#includebits/stdc.husingnamespacestd;intmain(){cout########## 一站式掌握信奥赛知识! ##########;cout############# 冲刺信奥赛拿奖! #############;cout###### 课程购买后永久学习不受限制! ######;return0;}1、csp信奥赛高频考点知识详解及案例实践CSP信奥赛C动态规划https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转CSP信奥赛C标准模板库STLhttps://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转信奥赛C提高组csp-s知识详解及案例实践https://blog.csdn.net/weixin_66461496/category_13113932.html2、csp信奥赛冲刺一等奖有效刷题题解CSP信奥赛C初赛及复赛高频考点真题解析持续更新https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转CSP信奥赛C一等奖通关刷题题单及题解持续更新https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转3、GESP C考级真题题解GESP(C 一级二级三级)真题题解持续更新https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转GESP(C 四级五级六级)真题题解持续更新https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转GESP(C 七级八级)真题题解持续更新https://blog.csdn.net/weixin_66461496/category_13117178.html4、CSP信奥赛C竞赛拿奖视频课https://edu.csdn.net/course/detail/40437 点击跳转· 文末祝福 ·#includebits/stdc.husingnamespacestd;intmain(){cout跟着王老师一起学习信奥赛C;cout 成就更好的自己 ;cout csp信奥赛一等奖属于你! ;return0;}