这是一道题用动态规划来做的话就是使用状态压缩,将糖果的每一种组合用二进制来表示
如:dp[i]就用来表示i状态下,所需要买的最小包数,假设i=5,用二进制表示就是101.它代表一号位有该种
类的糖果,二号位没有,三号位有。
在做这道题之前需要掌握位运算符
<< 代表左移运算符,将十进制数按二进制表示并且将它左移如2<<1,相当于10变成100,乘2
>> 右移运算符,同上
| 按位或,将十进制用二进制表示,每一位进行或运算,都是0则为0,其余为一
& 按位与,同上
#include <bits/stdc++.h>
using namespace std;
int nn[101];
int dp[1<<20];//因为题目要求20种糖果,所以有2的20次方种组合
int main(){
int n,m,k;
cin>>n>>m>>k;
int tatol=(1<<m)-1;//计算实际的组合数量
memset(dp,-1,sizeof dp);
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=0;j<k;j++){
int x;
cin>>x;
cnt|=(1<<x-1);//将每一包的糖果种类都按位或用cnt来表示
}
dp[cnt]=1;//并将cnt组合方式的最小包数置为1
nn[i]=cnt;//用nn数组来存储第i包的组合方式
}
for(int i=1;i<=tatol;i++){//遍历所有组合方式
if(dp[i]!=-1){//找出已经存在的组合方式
for(int j=0;j<n;j++){//遍历包数,并将第j包的组合方式和i按位或变成新的组合
if(dp[i|nn[j]]==-1||dp[i|nn[j]]>dp[i]+1){新的组合方式如果不存在或者太大都可以改变其值
dp[i|nn[j]]=dp[i]+1;
}
}
}
}
cout<<dp[tatol];
}