【算法每日一练]-动态规划(保姆级教程 篇17 状态压缩)

news2024/11/23 15:38:29

 目录

今日知识点:

把状态压缩成j,dp每行i的布置状态,从i-1和i-2行进行不断转移

把状态压缩成j,dp每行i的布置状态,从i-1行进行状态匹配,然后枚举国王数转移

 POJ1185:炮兵阵地

思路:

题目:互不侵犯

思路:


        

        

 POJ1185:炮兵阵地

在N*M(N<100,M<10)的地图上布置炮兵,H格子为山地不能布置,P格子为平原可以布置。炮兵的攻击范围是沿横向左右各两格,沿纵向上下个两格子
炮兵之间不能误伤。问在整个地图中最多能拜访多少个炮兵?
5 4
PHPP
PPHH
PPPP
PHPP
PHHP

        

思路:

还是那么句话,每个格子都有2种状态,如果搜索就要把所有结果都跑出来,所以只能使用状压dp 。      

而且方程的转移和上一行的状态有关,但是状态又太多了,故要状态压缩。

首先要对行进行状态压缩(对列的话太大了,枚举2^100还不如不压缩呢),我们每次确定行的状态都需要考虑:
1.横向方案    2.横向方案是否和地图匹配     3.是否和i-1行i-2行冲突
设置dp[i][j][k]表示第i行为第j状态,第i-1行为第k状态时 对应的前i行放置的最大炮兵数。
转移方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);(num是对应状态的炮兵个数)

(j是第i行的方案,k是第i-1行的方案,t是i-2行的方案)
存每行的可能状态:左右相邻1个间隔和2个间隔都不能炮兵(就是可能的横向方案)
存图:(1,1)开始存。0表示平原,1表示山地,那么在放置的时候不能出现同1(在山地放炮兵),所以x&y=0是合法的(保证合法的是0就行了)
是否冲突:第i行和第i-1行,第i-2行 不能出现有一列同1(两行都放炮兵),所以x&y=0是合法的

        
【注意】:外面每行i循环一次,其次里面是第i行的每个状态j循环一次(找到合适的j),然后是第i-1行的每个状态k循环一次(供第i行找到合适的k),
接着是第i-2行的每个状态t循环一次(供第i-1行找到合适的t)

#include <bits/stdc++.h>
using namespace std;
int n,m,top;
char mp[110][20];
int num[70];//num存放状态对应的炮兵个数
int ok[70],cur[70];//ok表示横向可能的方案,cur是我们存的地图行
int dp[110][70][70];

bool check(int x){
	if(x&(x<<1))return 0;//相邻1间隔是否合法
	if(x&(x<<2))return 0;//相邻2间隔是否合法
	return 1;
}

void init(){//统计所有的可能合法状态,最多60种
	top=0;
	for(int i=0;i<(1<<m);i++){//不能取等,不能取等!!!
		if(check(i))ok[top++]=i;
	}
}

int count(int x){//统计x二进制中1的个数
	int cnt=0;
	while(x){
		if(x&1)cnt++;
		x=x>>1;
	}
//	while(x){//这个更快
//		cnt++;
//		x&=(x-1);
//	}	
	return cnt;
}

int solve(){
	int ans=0;
	memset(dp,-1,sizeof(dp));
	for(int j=0;j<top;j++){//初始化第一行的状态
		num[j]=count(ok[j]);//记录每个正确状态的炮兵个数
		if(!(ok[j]&cur[1])){//和地图匹配
			dp[1][j][0]=num[j];//第一行状态为j,上一行状态为0(知道为啥从(1,1)开始初始化了把)
			ans=max(ans,dp[1][j][0]);
		}
	}

	for(int i=2;i<=n;i++){//处理每一行
		for(int j=0;j<top;j++){//遍历第i行的可能方案
			if(ok[j]&cur[i])continue;//是否和地图匹配
			for(int k=0;k<top;k++){//遍历第i-1行的可能方案
				if(ok[j]&ok[k])continue;//此行和上一行是否匹配(不用再判断和地图是否匹配,不匹配dp是-1,不影响的)
				for(int t=0;t<top;t++){//遍历上二行可能方案
					if(ok[j]&ok[t])continue;//此行和上二行是否匹配
					dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);
				}
				if(i==n)ans=max(ans,dp[i][j][k]);//不要放在外面套3个for取max
			}
		}
	}
	return ans;
}
int main(){
	while(cin>>n>>m){
		init();
		for(int i=1;i<=n;i++){
			scanf("%s",mp[i]+1);//加1是为了从1下标开始存
		}
		for(int i=1;i<=n;i++){
			cur[i]=0;
			for(int j=1;j<=m;j++){
				if(mp[i][j]=='H')//同样的,不能放的地方存1
					cur[i]+=(1<<(m-j));
			}
		}
		cout<<solve();
	}
}

        

        

题目:互不侵犯

思路:

可以看到和炮兵阵地题非常像,跑不了是状压dp。

还是那句话,每个方格都有两种状态,搜索的话必然是要全部搜索一下,放弃吧(况且,不谈超时,你真的把本道题的dfs其实也够呛的)。

设置dp[i][j][k]表示第i行为j状态时已经放了k个国王对应的方案数。

转移方程:dp[i][j][k]=dp[i-1][i-1行所有的合法状态][k-对应状态的国王数];

然后就是对状态的处理:

行内状态:我们要保证相与出0合法,非0不合法。那么对s行,

有:(((s<<1)&s==0)&&((s>>1)&s)==0)算合法,

等价于这个写法:(((s<<1)|(s>>1))&s)==0。   千万别少写红色括号!!!
行间状态:((s2&s1==0)&&((s2>>1)&s1==0)&&((s2<<1)&s1)==0)才算合法,

等价于:(((s2|(s2>>1)|(s2<<1))&s1)==0。

循环方式:首先是每行,然后选择该行状态,然后是上行状态,判断两行状态是否匹配,如果匹配就枚举国王数,最后转移方程!

#include <bits/stdc++.h>
using namespace std;
int num,n,k;//ok存正确的行状态,cnt存状态对应的国王数
long long dp[10][100][2000],cnt[2000],ok[2000];
int main(){
	cin>>n>>k;
	for(int s=0;s<(1<<n);s++){//遍历出所有的正确状态i
		int tot=0,tmp=s;
		while(tmp){
			if(tmp&1)tot++;tmp>>=1;
		}
		cnt[s]=tot;//存每个状态的国王数
		if((((s<<1)|(s>>1))&s)==0) ok[++num]=s;
	}
	dp[0][0][0]=1;
	for(int i=1;i<=n;i++){//从第一行开始转移
		for(int ss1=1;ss1<=num;ss1++){
			int s1=ok[ss1];//选择第一行的状态
			for(int ss2=1;ss2<=num;ss2++){
				int s2=ok[ss2];//选择上一行的状态
				if(((s2|(s2<<1)|(s2>>1))&s1)==0){//如果这两行状态合法
					for(int j=0;j<=k;j++){//对国王数进行枚举转移
						if(j-cnt[s1]>=0)
							dp[i][j][s1]+=dp[i-1][j-cnt[s1]][s2];
					}
				}
			}
		}
	}
	long long ans=0;
	for(int i=1;i<=num;i++)
		ans+=dp[n][k][ok[i]];
	cout<<ans;
}

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

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

相关文章

IP地址中网络号的查看方法

IP地址是互联网中设备的标识&#xff0c;它由网络号和主机号两部分组成。网络号用于标识设备所连接的网络&#xff0c;而主机号则用于标识该网络中的具体设备。了解如何查看IP地址中的网络号对于网络管理员和需要进行网络配置的用户来说至关重要。虎观代理将介绍几种常见的查看…

第⑫讲:Ceph集群OSD扩缩容中Reblanceing数据的重分布

文章目录 1.Reblanceing数据重分布的概念2.验证Reblanceing触发的过程3.Reblanceing细节4.临时关闭Reblanceing机制 1.Reblanceing数据重分布的概念 当集群中OSD进行扩缩容操作后&#xff0c;会触发一个Reblanceing数据重分布的机制&#xff0c;简单的理解就是将扩缩容前后OSD…

windows下使用ZLMediaKit-API+FFmpeg+opengl拉取解码播放流媒体

ZLMediaKit简介 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;和SRS类似&#xff0c;功能强大&#xff0c;性能优异&#xff0c;提供多种支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV/GB28181/HTTP-TS/WebSocket-TS/HTTP-fMP4/WebSocket-fMP4/MP4/…

插入排序解读

在众多的排序算法中&#xff0c;插入排序以其直观易懂和在某些特定场景下的高效性而备受青睐。今天&#xff0c;我们就来深入探索一下插入排序的原理、实现方式以及它的优缺点。 一、算法原理 插入排序相当于打牌中抓牌插入的方式。插入排序的工作方式是通过构建有序序列&…

007高并发内存池_回收内存

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;高并发内存池 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言一、ThreadCache回收内存二、CentralCache回收内存2.1 建立映射 三、PageCache回收内存 小结 前言 …

Google视觉机器人超级汇总:从RT、RT-2到AutoRT/SARA-RT/RT-Trajectory、RT-H

前言 随着对视觉语言机器人研究的深入&#xff0c;发现Google的工作很值得深挖&#xff0c;比如RT-2 ​想到很多工作都是站在Google的肩上做产品和应用&#xff0c;​Google真是科技进步的核心推动力&#xff0c;做了大量大模型的基础设施&#xff0c;服(推荐重点关注下Googl…

C语言——关于指针运算的例题分析

1.指针运算中关于 sizeof 和 strlen 的例题分析 1. sizeof(数组名)&#xff0c;这⾥的数组名表⽰整个数组&#xff0c;计算的是整个数组的⼤⼩。 2. &数组名&#xff0c;这⾥的数组名表⽰整个数组&#xff0c;取出的是整个数组的地址。 3. 除此之外所有的数组名都表⽰…

SpringBoot之SpringBoot整合MyBatis

本章详情 使用SpringBoot和MyBatis通过注解的方式操作数据库使用SpringBoot和MyBatis通过XML配置文件的方式操作数据库 项目搭建 1. 打开idea,选择Create New Project 2.选择Spring Initializer,然后点击Next 3.填写组织&#xff0c;坐标等信息&#xff0c;然后点击Next 4.选…

信息泄露漏洞的JS整改方案

引言 &#x1f6e1;️ 日常工作中&#xff0c;我们经常会面临线上环境被第三方安全厂商扫描出JS信息泄露漏洞的情况&#xff0c;这给我们的系统安全带来了潜在威胁。但幸运的是&#xff0c;对于这类漏洞的整改并不复杂。本文将介绍几种可行的整改方法&#xff0c;以及其中一种…

LeetCode-347. 前 K 个高频元素【数组 哈希表 分治 桶排序 计数 快速选择 排序 堆(优先队列)】

LeetCode-347. 前 K 个高频元素【数组 哈希表 分治 桶排序 计数 快速选择 排序 堆&#xff08;优先队列&#xff09;】 题目描述&#xff1a;解题思路一&#xff1a;哈希表记录出现次数&#xff0c;然后用最小堆取&#xff0c;因为每次都是弹出最小的&#xff0c;剩下的一定是K…

【鸿蒙开发】系统组件Column

Column组件 Column沿垂直方向布局的容器。 接口&#xff1a; Column(value?: {space?: string | number}) 参数&#xff1a; 参数名 参数类型 必填 参数描述 space string | number 否 纵向布局元素垂直方向间距。 从API version 9开始&#xff0c;space为负数或者…

error:LNK2005 已经在*.obj中定义 的原因分析及对策

LNK2005是一个重复定义错误&#xff0c;造成LNK2005主要有以下几种情况&#xff1a; 目录 全局变量的重复定义 情况A&#xff1a;全局变量在.cpp文件中的多次声明 情况B&#xff1a;变量名重复 头文件的包含重复 解决方案 #ifndef标识符宏定义 pragma once预编译 头文件…

C++第十五弹---string基本介绍(一)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、什么是STL 2、STL的版本 3、STL的六大组件 4、STL的重要性 5、如何学习STL 6、STL的缺陷 7、为什么学习string类 7.1、C语言中的字符串…

autodl常用工具命令

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 tar/zip命令镜像版本参考torch包全版本下载torch和cuda版本对应conda命令conda打包conda 环境重命名conda环境复制和转移conda环境删除 tar/zip命令 参考链接 文件目录打包&#x…

macU盘在电脑上读不出来 u盘mac读不出来怎么办 macu盘不能写入 Tuxera NTFS for Mac免费下载

对于Mac用户来说&#xff0c;使用U盘是很常见的操作&#xff0c;但有时候可能会遇到Mac电脑无法读取U盘的情况&#xff0c;这时候就需要使用一些特定的工具软件来帮助我们解决问题。本文就来告诉大家macU盘在电脑上读不出来是怎么回事&#xff0c;u盘mac读不出来怎么办。 一、m…

PTA题解 --- 静静的推荐(C语言)

今天是PTA题库解法讲解的第七天&#xff0c;今天我们要讲解静静的推荐&#xff0c;题目如下&#xff1a; 解题思路&#xff1a; 这个问题的核心在于如何在满足给定条件的情况下&#xff0c;最大化推荐学生的数量。首先&#xff0c;我们需要过滤出所有天梯赛成绩不低于175分的学…

3.2.k8s搭建-kubeadm

目录 一、虚拟机准备 二、所有节点环境准备 1.所有节点做hosts解析 2.所有节点重新命名 3.所有节点安装docker 4.所有节点为docker做linux内核转发 5.所有节点配置docker 6.所有节点关闭swap分区 7.所有节点验证网卡硬件编号是否冲突 8.所有节点配置允许iptables桥接…

Nginx配置文件修改结合内网穿透实现公网访问多个本地web站点

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…

水质监测站解析

TH-LSZ05水质监测站作为水资源保护和环境管理的重要工具&#xff0c;其功能和作用正日益受到人们的重视。随着科技的不断进步&#xff0c;水质监测站也在不断更新和完善&#xff0c;以适应不同场合和需求的监测任务。 首先&#xff0c;在技术创新方面&#xff0c;水质监测站正…

域控网络的创建

打进内网的方法 1.web服务器 域控创建 配置自己的ip winr&#xff1a;ncpa.cpl 然后属性将自己电脑的ip修改为静态ip 将DNS 修改为自己的ip 输入 winR 输入dcpromo 创建一个域 名为 cc.com 尝试去ping通 并将DNS 修改为自动 看看ping通的区别 在另一台电脑DNS修改为刚刚…