【算法每日一练]-动态规划(保姆级教程 篇17 状态压缩)#POJ1185:炮兵阵地 #互不侵犯

目录

今日知识点:

把状态压缩成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/484491.html

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

相关文章

代码随想录|Day27|贪心02|122.买卖股票的最佳时机II、55.跳跃游戏、45.跳跃游戏II

122.买卖股票的最佳时机II 本题可以将最终利润分解为每日利润&#xff1a; 假如第 0 天买入&#xff0c;第 3 天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[2] - prices[1]) (prices[1] - prices[0])。 如下图所…

机器人流程自动化技术(RPA)金融应用指南

1 范围 本文件提供了机器人流程自动化技术在金融领域应用的参考框架、技术设计、场景应用、安全管理、 成效评估等指南。 本文件适用于金融机构开展机器人流程自动化技术应用的产品设计、软件开发、系统评估等。 2 规范性引用文件 下列文件中的内容通过文中的规范性引用而构成…

深入探索JDK动态代理:从入门到原理的全面解析

文章目录 基本概念入门案例实现JDK动态代理的步骤入门实操拓展--动态生成代理类的几种方法方式一&#xff1a;通过getProxyClass方法获取代理实例方式二&#xff1a;通过newProxyInstance方法获取代理实例&#xff08;常用&#xff01;&#xff09;方式三&#xff1a;通过Lambd…

python--初学函数

函数&#xff08;function&#xff09;&#xff1a; 什么是函数&#xff1f; 具有名称的&#xff0c;是为了解决某一问题&#xff0c;功能代码的集合&#xff0c;叫做函数 python中函数如何定义&#xff1a;def>define function定义函数 def function_name([args临时变量…

Oracle 11G备份集中控制文件和spfile被异常删除

坐标大理&#xff0c;苍山下&#xff0c;洱海旁&#xff0c;风花雪月&#xff01;&#xff01; 今日一大早就接到一个case&#xff0c;根据客户描述&#xff0c;大概意思是昨天晚上发现18号的ctl和spfile无故消失&#xff0c;备份策略是一周一个0级增量备份&#xff0c;每日进…

数据库系统原理实验报告3 | 数据定义

整理自博主本科《数据库系统原理》专业课自己完成的实验报告&#xff0c;以便各位学习数据库系统概论的小伙伴们参考、学习。 专业课本&#xff1a; ———— 本次实验使用到的图形化工具&#xff1a;Heidisql 目录 一、实验目的 二、实验内容及步骤 1、创建数据库educ及其基…

自媒体洗稿软件文心一言api洗稿软件介绍

大家好&#xff0c;我是淘小白~ 这几天给一个客户写了一个文心一言api洗稿的软件。 一、客户要求&#xff1a; 1、采集头条文章&#xff08;软件内置可采集头条文章网址、微信文章网址、搜狐文章网址&#xff09; 2、调用文心一言api 3、多线程并发 4、逐段改写文章 5、…

关于YOLOv9项目中使用已有模块自由改进的教程

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 1. 文件说明 在YOLOv5-v9&#xff0c;模型的结构是以yaml文件的存储。我们可以在原有的yaml基础上增、减、改模块&#xff0c;创作我们自己的模型。 …

springboot3+jdk17+MP整合最新版jersey详细案例,正真做到拿来即用

如题&#xff0c;springboot3.x java17 MP 整合最新jersey&#xff0c;各种请求类型&#xff08;实战/详解&#xff09; 文件上传下载 jersey资源注册 拦截器&#xff08;JWT&#xff09; 跨域处理 全局异常 Valid注解校验 等等 &#xff0c;除非你必须整合security&am…

五、分布式锁-redission

源码仓库地址&#xff1a;gitgitee.com:chuangchuang-liu/hm-dingping.git 1、redission介绍 目前基于redis的setnx特性实现的自定义分布式锁仍存在的问题&#xff1a; 问题描述重入问题同一个线程无法多次获取统一把锁。当方法A成功获取锁后&#xff0c;调用方法B&#xff0…

深度学习pytorch——GPU加速(持续更新)

使用 .to(device)&#xff0c;以前使用 .cuda() &#xff0c;但是现在基本不使用了。 代码示例&#xff1a; 查看电脑GPU运行情况&#xff1a; 使用Ctrl Shift ESC快捷键&#xff1a;

【DP】01背包问题与完全背包问题

一、01背包问题 有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数&…

初探Flink集群【持续更新】

周末下雨&#xff0c;倒杯茶&#xff0c;在家练习Flink相关。 开发工具&#xff1a;IntelliJ Idea 第一步、创建项目 打开Idea&#xff0c;新建Maven项目&#xff0c;包和项目命名 在pom.xml 文件中添加依赖 <properties><flink.version>1.13.0</flink.vers…

SQLServer TRY_CONVERT函数

TRY_CONVERT&#xff1a;数据库中的安全转换利器 在数据库操作中&#xff0c;数据类型转换是一个常见的需求。然而&#xff0c;传统的转换方法在面对无法转换的数据时&#xff0c;往往会抛出错误&#xff0c;影响程序的稳定性和用户体验。为了解决这个问题&#xff0c;SQL Serv…

学习vue3第十节(插槽v-slot)

本节主要介绍一下 v-slot 插槽指令&#xff0c;以及插槽相关内容 1、定义&#xff1a; 子组件给父组件提供使用的一个位置&#xff0c;使用<slot></slot>表示&#xff0c;父组件可以在这个位置填充任何代码&#xff1b; 2、默认插槽 匿名插槽&#xff1a;会自定…

如何设计循环队列(两种方法)

文章目录 前言一、方法一:数组法二、方法二.链表法总结 前言 前面有提到过队列的知识&#xff0c;这次来说一下怎么设计一个循环队列 一.循环队列&#xff08;力扣&#xff09; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资…

seleniumUI自动化实例(CSDN发布文章)

1.CSDN登陆成功后&#xff0c;点击发布 源码&#xff1a; #点击首页中的发布按钮 CSDNconf.driver.find_element(By.LINK_TEXT,"发布").click() time.sleep(15) 2.输入标题 #输入文章标题&#xff0c;标题格式“selenium UI自动化测试实例今天的日期” CSDNconf.d…

JavaScript中的Lexical Environment

概要 本文主要介绍JavaScript中的一个重要概念Lexical Environment&#xff0c;它可以帮助我们解释我们为什么可以通过嵌套方法&#xff0c;共享数据&#xff0c;以及为什么可以在函数中定义一个和全局变量同名的变量&#xff0c;并且不会影响到全局变量。 基本分析 基本概念…

leetcode 2671

leetcode 2671 题目 例子 思路1 使用哈希&#xff0c; unordered_map 是基于hash 实现的key,val 存储。 代码1 class FrequencyTracker {unordered_map<int, int>m;public:FrequencyTracker() { }void add(int number) {if(m.find(number) m.end()){m.insert({num…

机器学习 | 期望最大化(EM)算法介绍和实现

在现实世界的机器学习应用中&#xff0c;通常有许多相关的特征&#xff0c;但只有其中的一个子集是可观察的。当处理有时可观察而有时不可观察的变量时&#xff0c;确实可以利用该变量可见或可观察的实例&#xff0c;以便学习和预测不可观察的实例。这种方法通常被称为处理缺失…