状压dp 理论例题 详解

news2024/10/6 2:23:26

状压dp

四川2005年省选题:互不侵犯

首先我们可以分析一下,按照我们普通的思路,就是用搜索,枚举每一行的每一列,尝试放下一个国王,然后标记,继续枚举下一行

那么,我们的时间复杂度就拥有了:
O ( 9 9 ) O(9^9) O(99)
计算方法:

因为是 n × n n\times n n×n 的棋盘,所以每行都会有至多9列( n ≤ 9 n\le 9 n9

然而我们每行都会有 n n n 种状态,所以我们的时间复杂度就是 O ( n n ) O(n^n) O(nn) ,即 O ( 9 9 ) O(9^9) O(99)

不过嘛——

所以我们是肯定不能采用的

这个时候,我们就需要学到一个 鬼东西 ——状态压缩dp!!

状压dp介绍——

所谓状压,字面翻译,就是把 复杂的状态 简化为 简洁的n进制数来表示

例如这道题

因为dp的状态转移,无非就是放和不放,所以我们就可以很容易地想到,用二进制的01串来表示,例子——

010001000

表示在第2列和第6列放国王,其余不放。

( 010001000 ) 2 (010001000)_2 (010001000)2 = ( 136 ) 10 (136)_{10} (136)10

因为 n ≤ 9 n\le 9 n9 ,所以这个数 ≤ 2 9 \le 2^9 29 ≤ 512 \le 512 512

那么我们需要进行一下判断,即满足什么条件时,可以放置这个国王

条件判断:

首先因为是二维的关系,我们先来判断行的关系,即一行一行地判断,看看上一行所放置的国王,限制了这一行哪些国王的放置

扫雷都玩过吧,附近的八个格子,设国王放置在 (x,y) 的地方,我们将它简化为以下关系:(x为行,y为列)
( x − 1 , y − 1 )       ( x − 1 , y )       ( x , y + 1 ) ( x , y − 1 )       ( x , y )       ( x , y + 1 ) ( x + 1 , y − 1 )       ( x + 1 , y )       ( x + 1 , y + 1 ) (x-1,y-1)\ \ \ \ \ (x-1,y)\ \ \ \ \ (x,y+1) \\ (x,y-1)\ \ \ \ \ (x,y)\ \ \ \ \ (x,y+1) \\ (x+1,y-1)\ \ \ \ \ (x+1,y)\ \ \ \ \ (x+1,y+1) (x1,y1)     (x1,y)     (x,y+1)(x,y1)     (x,y)     (x,y+1)(x+1,y1)     (x+1,y)     (x+1,y+1)

显然,如果上一行的 i 列放置了国王,那么下一行的 i-1,i,i+1 都不可以放置

那么如何判断呢

我们不难想到二进制的 左移右移运算符 ,目的是可以将目标 i 移到左于右的地方,进行判断

判断方法:

如果我们这一行的第 j 列需要放国王,那么上一行的 (i<<1),(i>>1),i 都不可为1,那么我们就可以运用位运算符 & 。有一位是1答案就为1,换句话说,只要 上下行同列放了两个国王 ,就不合法

再来说下列的关系

如果在同一列,左移右移旁边都没有,则是合法的(具体可以联系行的关系进行思考)

那么我们应该如何设用来dp的 f 数组, 状态转移方程 又该怎么写呢

我们不难想到可以一行一行的枚举(上文已提到),即设 f 数组 f[i][j][l] 表示现在在第 i 行,已经放了 j 个国王,所有方案为 l (这就是状压dp的精髓所在)

状态转移方程:

f ( i , j , l ) = ∑ f ( i − 1 , x , l − s t a ( j ) ) f(i,j,l)=\sum f(i-1,x,l-sta(j)) f(i,j,l)=f(i1,x,lsta(j))

代码(加过注释的):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=15,MAXM=85,MAXS=(1<<9)+5;
int n,k;
ll f[MAXN][MAXM][MAXS],ans;
int cnt,tmp,tot;
int num[MAXS],s[MAXS];
int s1,s2;
int main(){
	scanf("%d%d",&n,&k);
	f[0][0][0]=1;
	for(int i=0;i<(1<<n);i++)
	{
		cnt=0,tmp=i;
		while(tmp)
		{
			if(tmp&1) ++cnt;//cnt统计i的二进制有放了多少国王
			tmp=tmp>>1;//继续枚举 
		}
		num[i]=cnt;//num[i]表示第i种状态有num[i]个国王放在那里 
		if(!(((i<<1)|(i>>1))&i)) s[++tot]=i;//判断行内放国王合不合法,比较抽象 
	}
	for(int i=1;i<=n;i++)//遍历每一行 
	{
		for(int j=1;j<=tot;j++)//枚举这一行每种可能的状态 
		{
			s2=s[j];//s2代表这一行的状态 
			for(int l=1;l<=tot;l++)//前一行的每种状态 
			{
				s1=s[l];//s1代表上一行的状态 
				if(!(s1&s2)&&(!((s1<<1)&s2))&&(!((s1>>1)&s2)))//行间的限制判断 
					for(int a=0;a<=k;a++)
						if(a-num[s2]>=0)
							f[i][a][s2]+=f[i-1][a-num[s2]][s1];
			}
		}
	}
	for(int i=1;i<=tot;i++)
		ans+=f[n][k][s[i]];
	printf("%lld\n",ans);
	return 0;
}

AC记录

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是X电容和Y电容?

先补充个知识&#xff1a; 一、什么是差模信号和共模信号 差模信号&#xff1a;大小相等&#xff0c;方向相反的交流信号&#xff1b;双端输入时&#xff0c;两个信号的相位相差180度 共模信号&#xff1a;大小相等。方向相同。双端输入时&#xff0c;两个信号相同。 二、安规…

嵌入式5-6QT

1> 思维导图 2> 自由发挥应用场景&#xff0c;实现登录界面。 要求&#xff1a;尽量每行代码都有注释。 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置标题this->setWindowTitle("MYQQ");//设置图标this…

5月6号作业

申请该结构体数组&#xff0c;容量为5&#xff0c;初始化5个学生的信息 使用fprintf将数组中的5个学生信息&#xff0c;保存到文件中去 下一次程序运行的时候&#xff0c;使用fscanf&#xff0c;将文件中的5个学生信息&#xff0c;写入(加载)到数组中去&#xff0c;并直接输出学…

PyTorch机器学习实现液态神经网络

大家好&#xff0c;人工智能的发展催生了神经网络这一强大的预测工具&#xff0c;这些网络通过数据和参数优化生成预测&#xff0c;每个神经元像逻辑回归门一样工作。结合反向传播技术&#xff0c;模型能够根据损失函数来调整参数权重&#xff0c;实现自我优化。 然而&#xf…

题目:排序疑惑

问题描述&#xff1a; 解题思路&#xff1a; 做的时候没想到&#xff0c;其实这是以贪心题。我们可以每次排最大的区间&#xff08;小于n&#xff0c;即n-1大的区间&#xff09;&#xff0c;再判断是否有序 。因此只需要分别判断排&#xff08;1~n-1&#xff09;和&#xff08;…

算法学习:二分查找

&#x1f525; 引言 在现代计算机科学与软件工程的实践中&#xff0c;高效数据检索是众多应用程序的核心需求之一。二分查找算法&#xff0c;作为解决有序序列查询问题的高效策略&#xff0c;凭借其对数时间复杂度的优越性能&#xff0c;占据着算法领域里举足轻重的地位。本篇内…

open 函数到底做了什么

使用设备之前我们通常都需要调用 open 函数&#xff0c;这个函数一般用于设备专有数据的初始化&#xff0c;申请相关资源及进行设备的初始化等工作&#xff0c;对于简单的设备而言&#xff0c;open 函数可以不做具体的工作&#xff0c;你在应用层通过系统调用 open 打开设备…

Unity 修复Sentinel key not found (h0007)错误

这个问题是第二次遇到了&#xff0c;上次稀里糊涂的解决了&#xff0c;也没当回事&#xff0c;这次又跑出来了&#xff0c;网上找的教程大部分都是出自一个人。 1.删除这个路径下的文件 C:\ProgramData\SafeNet Sentinel&#xff0c;注意ProgramData好像是隐藏文件 2.在Windows…

04-19 周五 GitHub actions-runner 程序解释

04-19 周五 GitHub actions-runner 程序解释 时间版本修改人描述2024年4月19日17:26:17V0.1宋全恒新建文档 简介 本文主要描述了actions-runner-linux-x64-2.315.0.tar.gz这个github actions CI所需要的客户端安装包的重要文件和内容信息。有关GitHub actions 的配置&#xff…

利用matplotlib和networkx绘制有向图[显示边的权重]

使用Python中的matplotlib和networkx库来绘制一个有向图&#xff0c;并显示边的权重标签。 1. 定义了节点和边&#xff1a;节点是一个包含5个节点的列表&#xff0c;边是一个包含各个边以及它们的权重的列表。 2. 创建了一个有向图对象 G。 3. 向图中添加节点和边。 4. 设置了…

Elasticsearch:如何使用 Java 对索引进行 ES|QL 的查询

在我之前的文章 “Elasticsearch&#xff1a;对 Java 对象的 ES|QL 查询”&#xff0c;我详细介绍了如何使用 Java 来对 ES|QL 进行查询。对于不是很熟悉 Elasticsearch 的开发者来说&#xff0c;那篇文章里的例子还是不能单独来进行运行。在今天的这篇文章中&#xff0c;我来详…

外贸企业邮箱是什么?做外贸企业邮箱哪个好?

外贸企业邮箱是什么&#xff1f;外贸企业在进行跨国沟通时必不可少的工具就是外贸企业邮箱&#xff0c;外贸企业邮箱需要具备的条件就是海外邮件抵达率高、安全稳定、多语言沟通。而我们又怎么选择一个适合的外贸企业邮箱呢&#xff1f;小编今天带您一起了解。 一、外贸企业邮…

MySQL基础_5.多表查询

文章目录 一、多表连接1.1、笛卡尔积&#xff08;或交叉连接&#xff09; 二、多表查询&#xff08;SQL99语法&#xff09;2.1、内连接(INNER JOIN)2.2、内连接(INNER JOIN) 一、多表连接 多表查询&#xff0c;也称为关联查询&#xff0c;指两个或更多个表一起完成查询操作。 …

一款开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验

Snap.Hutao 胡桃工具箱是一款以 MIT 协议开源的原神工具箱&#xff0c;专为现代化 Windows 平台设计&#xff0c;旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合&#xff0c;提供了一套完整且实用的工具集&#xff0c;且无需依赖任何移动设…

Django开发实战之登录用户鉴权登录界面实现

Django自带的鉴权系统非常的安全&#xff0c;大家可以放心使用&#xff0c;那么如何使用呢&#xff1f; 1、首先需要检查settings文件种的INSTALLED_APPS&#xff0c;有没有这两部分内容&#xff1a; 2、检查中间件&#xff0c;比如这两个中间件&#xff0c;一个是用于登录&a…

【探秘地球宝藏】矿产资源知多少?

当我们仰望高楼林立的城市&#xff0c;乘坐便捷的交通工具&#xff0c;享受各种现代生活的便利时&#xff0c;你是否曾想过这一切背后的支撑力量&#xff1f;答案就藏在我们脚下——矿产资源&#xff0c;这些大自然赋予的宝贵财富&#xff0c;正是现代社会发展的基石。今天&…

使用ThemeRoller快速实现前端页面风格美化

使用ThemeRoller快速实现前端页面风格美化 文章目录 使用ThemeRoller快速实现前端页面风格美化一、ThemeRoller二、使用方法1.基本操作面板介绍2.直接用现成的配色风格——Gallery画廊3.自定义风格——Roll Your Own4.下载风格包并应用到页面 一、ThemeRoller ThemeRoller是jQ…

基于矩阵乘法的GPU烤机python代码(pytorch版)

前言 测试gpu前需要安装Anaconda、pytorch、tmux、nvitop。 单gpu 代码 import numpy as np from tqdm import tqdmProject &#xff1a;gpu-test File &#xff1a;gpu_stress.py Author &#xff1a;xxx Date &#xff1a;2024/4/20 16:13import argparse import …

力扣153. 寻找旋转排序数组中的最小值

Problem: 153. 寻找旋转排序数组中的最小值 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化左右指针left和right&#xff0c;指向数组的头和尾&#xff1b; 2.开始二分查找&#xff1a; 2.1.定义退出条件&#xff1a;当left right时退出循环&#xff1b; 2.2.当nums…

Java新手必看:快速上手FileOutPutStream类

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…