今天给大家带来新的篇章,动态规划问题下的状态压缩问题,首先我们得理解状态压缩的基本定义。状态压缩表示将若干状态压缩为2进制数来进行求解,通常与位运算相结合。
如dp[5][2],其中5的二进制为101,而2则表示选择了2个,且最后一个是2的最大/最小状态。
这里有几个常见的关于状态压缩的位运算定义:
1.取出x的第i位:x>>i&1
2.将x的第i位设置为1:x|=(1<<i)
3.将x的第i位反转:x^=(1<<i)
4.低于n位的数均为1:(1<<n)-1
题目描述
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1∼ M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。
输入描述
第一行包含三个整数 N,M,K。
接下来 N行每行 K 个整数 T1,T2,⋅⋅⋅,TK,代表一包糖果的口味。
其中,1≤N≤100,1≤M≤20,1≤K≤20,1≤Ti≤M。
#include <bits/stdc++.h>
using namespace std;
const int N=20;
using ll=long long;
ll dp[(1<<20)];
int a[105];
int main()
{
int n,m,k;
cin>>n>>m>>k;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
int x;cin>>x;
a[i]|=(1<<(x-1));
}
}
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=((1<<m)-1);j++){
dp[a[i]|j]=min(dp[a[i]|j],dp[j]+1);
}
}
if(dp[(1<<m)-1]>n)cout<<-1<<endl;
else cout<<dp[(1<<m)-1]<<endl;
return 0;
}
这道题是经典的状态压缩DP问题,我们可以发现,状态压缩DP的关键其实就在于如何把处理位运算之间的关系。同时要注意n的范围,一般在10-20之间可以考虑使用。
今天的分享就到这里,感谢大家的关注和点赞。