动态规划-状态压缩DP

今天给大家带来新的篇章,动态规划问题下的状态压缩问题,首先我们得理解状态压缩的基本定义。状态压缩表示将若干状态压缩为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之间可以考虑使用。

今天的分享就到这里,感谢大家的关注和点赞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值