状压DP(学习笔记)

news/2025/1/24 15:25:03/文章来源:https://www.cnblogs.com/XichenOC/p/18689567

简介:

状压 \(dp\) 很明显是将状态压缩后进行 \(dp\),这种算法多用于状态只有两种的情况,且一般给定范围较小,如 \(n \leq 16\) 等,遇到这种情况就可以考虑去状压 \(dp\)

前置知识:

我们知道一个数可以表示成二进制,如 \((25)_{10}=(1101)_2\) 那我们就可以将一个区间内所有的状态表示成二进制,然后在转换成十进制,这样就将一个区间内的状态压缩成一个数字。再由这个状态进行转移。

实现

这里给一道例题来看看状压 \(dp\) 的实现过程:
P1896 [SCOI2005] 互不侵犯

阅读完题目可以发现其,棋盘大小较小,那很明显是状压 \(dp\),那我们就将一行的状态给压缩起来,即在二进制中对应位就是在该列对应的位置,若这个位置上有棋那就为 \(1\) 反之为 \(0\) 那这样,就储存下来了。

那我们再来看看这些状态有什么限制:

  • 首先根据题意可以知道,同一行的棋子不能相邻,即其左右都不能有棋子,对应到二进制就是一个 \(1\) 左移一位和右移一位都不为 \(1\),那么我们可以用二进制的运算法则来看就相当于 (x<<1)&x==0 && (x>>1)&x==0,因为与运算要求是都为 \(1\) 才返回 \(1\) 那如果其左右两位返回的不是零,那很明显其左右两位有 \(1\) 就不符合要求。上面的关系还能写成 !(((x<<1)|(x>>1))&x)
  • 其次还要判断其是否在上面棋子的禁止范围内,那我们令 \(s1,s2\)分别代表当前行的状态和上一行的状态,那同理(s1<<1)&s2==0 && (s1>>1)&s2==0 && s1&s2==0。即左移一位,右移一位和不移都与上一行没有重复的 \(1\),同样可以写成!(((s1<<1)|(s1>>1)|s1)&s2),这样就可以在枚举时判断是否满足这两条性质,再来进行转移。

状态转移:

转移方程: 我们假定 \(dp[x][y][z]\) 表示第 \(x\) 行,用了 \(y\) 个棋子,当前行的状态为 \(z\) 的方案数。那很显然要先枚举行数 \(i\),在枚举当前行的状态 \(s1\) 与上一行的状态 \(s2\),最后在枚举用的棋子数 \(len\),那如果满足限制的前提下转移方程就为

\[dp[i][len][s1]+=dp[i-1][len-cnt[s1]][s2] \]

其中 \(cnt[s1]\)表示当前状态的所用棋子数。

初始化: 而对于第 \(0\) 行,用了 \(0\) 个棋子,状态为 \(0\) 的方案数为 \(1\),即:

\[dp[0][0][0]=1 \]

统计答案: 只需要统计最后一行,用完棋子的所有状态的方案数之和即可。

优化:

对于性质 \(1\)\(cnt[s1]\) 可以提前预处理出来。
暴力枚举所有的状态,对于每个状态都统计一下 \(1\) 的个数,即 \(cnt[s1]\)。然后看他是否满足性质 \(1\),若满足,就加入 \(ok[++num]\) 中,方便后面调用:

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2010;
int ok[N],cnt[N];
int dp[10][100][N];
signed main(){int n,m;scanf("%lld%lld",&n,&m);int num=0;for(int i=0;i<(1<<n);i++){int tot=0;int s=i;while(s){if(s&1)tot++;s>>=1;}cnt[i]=tot;if(!(((i<<1)|(i>>1))&i)){ok[++num]=i;}}dp[0][0][0]=1;for(int i=1;i<=n;i++){for(int j=1;j<=num;j++){for(int k=1;k<=num;k++){int s1=ok[j],s2=ok[k];if(!((s2|(s2<<1)|(s2>>1))&s1)){for(int len=0;len<=m;len++){if(len-cnt[s1]>=0){dp[i][len][s1]+=dp[i-1][len-cnt[s1]][s2];}}}}}}int ans=0;for(int i=1;i<=num;i++){ans+=dp[n][m][ok[i]];}printf("%lld",ans);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/874748.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

autocad Ribbon创建的一种新思路

之前开发的功能相对简单, 一个RibbonTab就把相关的功能展示出来了。 目前着手准备开发的功能, 需要多个RibbonTab, 且不想显示AutoCAD或Civil 3D自身的RibbonTab, 曾经想模拟3d3s的样子来切换RibbonTab, 但发现3d3s是将AutoCAD原生的Cuix和自己的RibbonTab结合到一起, 对…

Solon Cloud Gateway 开发:导引

Solon Cloud Gateway 是 Solon Cloud 体系提供的分布式网关实现(轻量级实现)。Solon Cloud Gateway 是 Solon Cloud 体系提供的分布式网关实现(轻量级实现)。 分布式网关的特点(相对于本地网关):提供服务路由能力 提供各种拦截支持1、分布式网关推荐 建议使用专业的分布…

Mac安装Prometheus + Grafana

一、安装Prometheus 1、下载安装 brew install prometheus2、安装路径 /opt/homebrew/Cellar/prometheus/3.1.0 3、修改配置文件 默认配置文件路径:/opt/homebrew/etc/prometheus.yml global:scrape_interval: 15sscrape_configs:- job_name: "prometheus"static_co…

Python基础6——装饰器(续) 递归 模块

1.函数1.1 参数当默认参数的值为可变类型时慎用# 不推荐使用以下代码 def func(data, value=[]):pass可以将默认参数的值改为None# 推荐使用以下代码 def func(data, value=None):if not value:value = []案例def func(data, value=[]):value.append(data)return valuev1 = fun…

C# Winform 在 Pancel 上绘制矩形

在C#的WinForms应用程序中,Panel控件本身不直接支持绘图功能,因为它不是一个绘图控件。不过,你可以通过在Panel上覆盖(override)OnPaint方法或者使用Graphics对象来在Panel上绘制图形。下面是如何实现这两种方法的示例: 方法1:覆盖OnPaint方法 可以通过重写Panel的OnPai…

SpringBoot使用SSE流,打tar包发版后出现问题

SpringBoot使用SSE流,打tar包发版后出现问题 以下纯个人实践,如有问题,还望指正~ 出现的问题 出现原因:本地调试SSE推送数据没有问题,但是通过打包为tar包发版之后,出现了以下报错: 主要问题就是: java.lang.IllegalArgumentException: Async support must be enabled …

【每日一题】20250124

读书就是这样好,无论心不在焉,板着长脸,只要考试及格,就是一个及格的人。【每日一题】 1.(20分) \(\hspace{0.6cm}\)如图所示,质量 \(M=2 \; \mathrm{kg}\) 的滑块套在光滑的水平轨道上,质量 \(m=1 \; \mathrm{kg}\) 的小球通过长 \(L=0.5 \; \mathrm{m}\) 的轻质细杆与…

Golang sync.pool源码解析

sync.Pool 是 Go 中用于对象复用的工具,可减少频繁创建和销毁对象的开销,从而优化内存使用和降低 GC 压力。本文通过分析其用法、真实案例及源码结构,详细解读了 sync.Pool 的读写流程及其背后的高效设计思想,为性能优化提供了实用参考。Golang sync.pool源码解析 - sync.p…

从靶场到实战:双一流高校多个高危漏洞

本文结合其它用户案例分析讲解挖掘某双一流站点的过程,包含日志泄露漏洞深入利用失败,到不弱的弱口令字典进入后台,再到最后偶遇一个貌似只在靶场遇到过的高危漏洞。本文结合其它用户案例分析讲解挖掘某双一流站点的过程,包含日志泄露漏洞深入利用失败,到不弱的弱口令字典…

Nginx 架构和安装

1.1 Nginx 概述 1.1.1 Nginx 介绍 Nginx:engine X ,2002年开发,分为社区版和商业版(nginx plus ) 2019年3月11日 F5 Networks 6.7亿美元的价格收购 Nginx是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器 解决C10K问题(10K Connect…

Linux命令大全-快速查询手册

访问地址: 线上访问:https://git.io/linux 开源社区:https://github.com/jaywcjlove/linux-command 简要介绍: Linux 命令大全搜索工具,内容包含 Linux 命令手册、详解、学习、搜集,中文解释,支持背景切换。主要功能: 当前仓库搜集了 580 多个 Linux 命令,是一个非盈利…

IPTVnator - 最方便的开源 IPTV 播放器

IPTVnator 是一款视频播放器应用程序,提供对 IPTV 播放列表播放(m3u、m3u8)的支持。该应用程序允许用户使用远程 URL 或从本地文件系统上传文件来导入播放列表。此外,它还支持 XMLTV 格式的 EPG 信息,可以通过 URL 提供。该应用程序是一个使用 Electron(目前正在迁移到 T…