蓝桥杯补题 状态压缩DP

蓝桥杯差一点进了国赛,考前还玩了一天游戏,现在想想真的难受。

先把题补了吧,5.11加油!

一开始一点头绪都没有,看了别人的题解发现是压状DP

动态规划博大精深。。。。

其实好像很好理解

压缩状态的DP有几个特征,

1. 有n组数据 那么可能性总数是  2^n ,就是每个数据取还是不取的问题, 

或者是结构由n个数据组成, 结果可能性也是  2^n 因为每种结果中每个数据有或者没有

其实就是针对集合的dp 使集合最终满足一定条件

2.其他特征也想不出来QAQ  可以从数据入手,比如一个数据很大,一个数据很小,就是n个物品有

1<<m种状态,n很大,m很小,也是可以往压状dp去向 

dp的模板好像也不是很固定

就是

 for(int i=0;i<n;i++)
    {
        for(int j=0;j<(1<<m);j++)
        {
            //进行操作
        }
    }

就是很难想, 做dp题目一定要动笔写状态转移方程!!!

应该是AC代码了

#include<iostream>
#include<algorithm>
#include<string.h>
#include<bits/stdc++.h>
using namespace std;
int dp[1048596];
int candy[105];
int n,m,k;
int main(){
	memset(dp,-1,sizeof(dp));
	cin>>n>>m>>k;
	int temp;
	int sum=0;
	for(int i=0;i<n;i++){
		sum=0;
		for(int j=0;j<k;j++){
			cin>>temp;
			sum=sum|(1<<(temp-1));
		}
		//cout<<sum<<endl;
		dp[sum]=1;
		candy[i]=sum;
	}
	for(int i=0;i<n;i++){
		for(int j=1;j<(1<<m);j++){
			if(dp[j]==-1)
				continue;
			else if(dp[j|candy[i]]==-1){
				dp[j|candy[i]]=dp[j]+1;
			}
			else {
				dp[j|candy[i]]=min(dp[j|candy[i]],dp[j]+1);
			}
		}
	}
	cout<<dp[(1<<m)-1]<<endl;
	return 0;
}

这题想法是吧一袋糖压缩成一个状态, 也便于存储,一个int存一袋糖,然后用上面的dp模板

在第二个循环for(int j ;j<(i<<m);j++)中间去判断dp[j]的状态,就是  j代表的是 现在有的糖的总类的压缩 ,

dp[ j ]代表需要的最少包的糖数能够达到这个状态。

在之前输入每包糖的状态的时候就初始化一下dp[ 每包糖的压缩状态 ] =1 

 

### 蓝桥杯省赛中的“最大和”相关真题及其解法 #### 题目背景 蓝桥杯竞赛中,“最大和”的题目通常涉及数组或矩阵的最大子序列、最大子矩阵等问题。这类问题的核心在于动态规划算法的应用以及如何高效地处理数据结构。 --- #### 1. **最大连续子序列和** 这是经典的“最大和”类问题之一,目标是从给定的一维数组中找到具有最大和的连续子序列。 ##### 动态规划思路 定义 `dp[i]` 表示以第 `i` 个元素结尾的最大子序列和,则状态转移方程为: ```plaintext dp[i] = max(dp[i-1] + nums[i], nums[i]) ``` 最终结果即为所有 `dp[i]` 的最大值。 ##### Python 实现代码 ```python def max_subarray_sum(nums): dp = [0] * len(nums) dp[0] = nums[0] for i in range(1, len(nums)): dp[i] = max(dp[i-1] + nums[i], nums[i]) # 状态转移 return max(dp) # 测试用例 nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] print(max_subarray_sum(nums)) # 输出应为 6 (子序列为 [4,-1,2,1]) ``` 此方法的时间复杂度为 O(n),空间复杂度可以通过优化降低到 O(1)[^1]。 --- #### 2. **二维矩阵中的最大子矩阵和** 此类问题是“最大连续子序列和”的扩展版本,适用于二维场景下的求解。 ##### 思路分析 通过将二维矩阵缩成一维来解决问题。具体做法如下: 1. 枚举每一列作为起始列; 2. 对于每一对起始列和结束列之间的区域,将其按行累加形成一个新的数组; 3. 使用上述一维最大子序列和的方法解决该新数组的最大和问题。 ##### Python 实现代码 ```python def max_matrix_sum(matrix): rows, cols = len(matrix), len(matrix[0]) result = float('-inf') for l in range(cols): # 左边界 row_sums = [0] * rows for r in range(l, cols): # 右边界 for i in range(rows): row_sums[i] += matrix[i][r] # 将当前列加入 current_max = temp = row_sums[0] for j in range(1, rows): temp = max(temp + row_sums[j], row_sums[j]) current_max = max(current_max, temp) result = max(result, current_max) return result # 测试用例 matrix = [ [1, -2, -3, 4], [5, 6, -7, 8], [-9, -10, 11, 12] ] print(max_matrix_sum(matrix)) # 输出应为 26 ``` 时间复杂度为 O(n³),其中 n 是矩阵边长[^2]。 --- #### 3. **其他变种问题** 除了以上两种经典形式外,还可能遇到一些变形问题,例如: - 找到两个不重叠子序列/子矩阵的最大和。 - 给定约束条件(如长度限制)下找最大和。 这些问题一般仍基于动态规划的思想,但在实现上需额外考虑约束条件的影响。 --- #### 结论 对于蓝桥杯省赛中的“最大和”类问题,掌握动态规划的基础理论至关重要。无论是针对一维还是二维的数据结构,都可以通过合理的设计减少冗余运算并提高效率。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值