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

 目录

今日知识点:

把状态压缩成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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

互联网大厂ssp面经之路:计算机网络part2

什么是 HTTP 和 HTTPS&#xff1f;它们之间有什么区别&#xff1f; a. HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是用于在Web上传输数据的协议。它们之间的区别在于安全性和数据传输方式。 b. HTTP是一种不安全的协议&…

算法训练营第二十一天(二叉树part7)

算法训练营第二十一天&#xff08;二叉树part7&#xff09; 530.二叉搜索树的最小绝对差 力扣题目链接(opens new window) 题目 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。 示例&#xff1a; 提示&#xff1a;树中至…

原来进制题如此简单

进制相关 二进制数与其他进制数之间的转化 二进制数转其他进制数&#xff08;十进制数除外&#xff09;一般不能直接转化&#xff0c;一般需要过度至十进制数&#xff0c;再转化为其他进制数。同理&#xff0c;其他进制数&#xff08;十进制数除外&#xff09;转二进制数也需过…

flutter多入口点entrypoint

native中引擎对象本身消耗内存(每个引擎对象约莫消耗42MB内存) 多引擎&#xff1a;native多引擎>启动>flutter多入口点entrypoint>多main函数>多子包元素集>多(子)程序 单引擎(复用)&#xff1a;native单引擎>复用启动>flutter多入口点entrypoint>多m…

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

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

使用yml文件配置python日志

新建一个logging.yml文件&#xff0c;内容如下&#xff1a; logging库提供了多个组件&#xff1a;Logger、Handler、Filter、Formatter&#xff1a; Logger 对象提供应用程序可直接使用的接口&#xff0c;供应用代码使用&#xff1b; Handler 发送日志到适当的目的地&#xff…

PMC管理中落实生产作业计划的思路与方法

在快节奏的现代商业环境中&#xff0c;PMC&#xff08;生产及物料控制&#xff09;管理对于确保企业生产流程的高效运转至关重要。生产作业计划的落实不仅关乎企业的生产效率和成本控制&#xff0c;更是企业竞争力的重要体现。那么&#xff0c;PMC管理中如何有效落实生产作业计…

上传应用程序到苹果应用商店的工具和要点

引言 在今天的移动应用市场中&#xff0c;将应用程序上传到苹果应用商店&#xff08;App Store&#xff09;是许多开发者的首要任务之一。然而&#xff0c;不同操作系统下的开发者可能需要使用不同的工具和遵循不同的要求来完成这一任务。本文将介绍在 macOS、Windows 和 Linu…

【C语言】:字符函数和字符串函数

这里写目录标题 1、strlen的使用和模拟实现2、strcpy的使用和模拟3、strcat 的使用和模拟实现4、strcmp 的使用和模拟实现5、strncpy 函数的使用6、strncat 函数的使用7、strncmp函数的使用8、strstr 的使用和模拟实现9、strtok 函数的使用10、strerror 函数的使用11、字符分类…

独家原创 | SCI 1区 高创新轴承故障诊断模型!

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Python轴承故障诊断 (一)短时傅里叶变换STFT Python轴承故障诊断 (二)连续小波变换CWT_pyts 小波变换 故障-CSDN博客 Python轴承故障诊断 (三)经验模态分解EMD_轴承诊断 …

MySQL数据库 数据库基本操作(四):表的增删查改(下)

1. 联合查询 注:联合查询是面试中的重点,只要考到sql,大多数情况下都考的是联合查询,而且联合查询也是我们学习中的难点. 1.1 笛卡尔积 在实际开发中,数据往往来自不同的表,所以要多表联合查询.多表查询是对多张表的数据笛卡尔积. 它们是两张表的各行数据通过全排列得到的. …

摩尔信使MThings之数据网关:Modbus转MQTT

由于现场设备和物联网云平台采用了不同的通信协议&#xff0c;而为了实现它们之间的互操作性和数据交换&#xff0c;需要进行协议转换。 MQTT作为一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;适用于连接分布式设备和传感器网络&#xff0c;而MODBUS协议则常用于工业…

ISG立式管道离心泵(管道增压泵)

一、设计特征 ISG立式管道离心泵是一种高效的水泵&#xff0c;它采用立式单级或多级离心泵的设计&#xff0c;使得电机轴与泵轴直接连接&#xff0c;减少了传输损失。该泵的主要部件包括电机、泵体、叶轮、轴封及泵盖等。与传统卧式泵相比&#xff0c;ISG泵占地面积小&#xff…

像用户一样测试:别掉链子

“掉链子”是一句俗语&#xff0c;比喻在关键时刻出故障&#xff0c;或者重要的事情本该做好却没做好。 “掉链子”的说法来自于自行车&#xff1a;在骑行过程中&#xff0c;链条通过链轮传送&#xff0c;带动车轮滚滚向前。当链条从链轮上脱落&#xff0c;就无法进行传动&…

k8s部署efk

环境简介&#xff1a; kubernetes: v1.22.2 helm&#xff1a; v3.12.0 elasticsearch&#xff1a; 8.8.0 chart包&#xff1a;19.10.0 fluentd: 1.16.2 chart包&#xff1a; 5.9.4 kibana: 8.2.2 chart包&#xff1a;10.1.9 整体架构图&#xff1a; 一、Elasticsearch安装…

跨境电商选品思路:12个方法和爆品法则(完结篇)

不管你是做亚马逊、速卖通、Shopee 、Lazada、美客多、eBay、SHEIN、Temu、Tiktok、shopify等跨境电商平台的卖家&#xff0c;选品思路一定要清楚&#xff0c;选到好品才是成为爆品的基础。店雷达继续给各位跨境商家分享12个大数据选品场景思路&#xff0c;错过其他选品场景思路…

建设智慧公厕有什么好处?@光明源,都有哪些功能?

在城市化进程不断加快的今天&#xff0c;智慧公厕作为城市基础设施的重要组成部分&#xff0c;正逐渐受到各地政府和管理者的重视。那么&#xff0c;建设智慧公厕到底有哪些好处&#xff1f;它们又都涉及哪些功能呢&#xff1f;让我们一起来探讨一下。 首先&#xff0c;建设智…

初学python记录:力扣1600. 王位继承顺序

题目&#xff1a; 一个王国里住着国王、他的孩子们、他的孙子们等等。每一个时间点&#xff0c;这个家庭里有人出生也有人死亡。 这个王国有一个明确规定的王位继承顺序&#xff0c;第一继承人总是国王自己。我们定义递归函数 Successor(x, curOrder) &#xff0c;给定一个人…

基于SpringBoot+Vue+Mysql的图书管理系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

[leetcode]只出现一次的数字Ⅲ

题目&#xff1a; 给你一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。 你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。 示例 1&…