Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
问题描述
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1 ∼ M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖
果。
输入格式
第一行包含三个整数 N、M 和 K。
接下来 N 行每行 K 这整数 T₁, T₂, · · · , TK,代表一包糖果的口味。
输出格式
一个整数表示答案。如果小明无法品尝所有口味,输出 −1。
样例输入
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
样例输出
2
评测用例规模与约定
对于 30% 的评测用例,1 ≤ N ≤ 20 。
对于所有评测样例,1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M。
思路
一道比较典型的状态压缩的题(说是比较是因为我一时竟然还不太会做)。
什么叫状态压缩?就是如果有一组状态,每个状态可以抽象为0和1,就可以把这组状态转换为唯一对应的二进制数字。
以这道题举例,对于任何口味,0代表没有品尝到,1代表品尝到。假如一共有20种口味,那么口味从1到20,用一个二进制数字的每一位代表。这样从到,每个数字代表唯一的一个状态,我们要求的就是的状态下最少买几包。
设二维状态dp(i,j)代表只买前i包的情况下达到状态i最少买几包。(若不可能达到就是无穷大) 则状态转移方程:
不难发现,可以将dp函数的第一维去掉,这样可以节省内存空间。详情看代码即可,点到即止。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxm=1<<20+5;
int dp[maxm];
const int maxn=100+5;
const int inf=0x3f3f3f3f;
int arr[maxn];
int main(){
int n,m,k;
cin>>n>>m>>k;
memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i=0;i<n;i++){
for(int j=0;j<k;j++){
int a;cin>>a;
arr[i]=arr[i]|(1<<(a-1));
}
dp[arr[i]]=1;
}
for(int j=0;j<n;j++){
for(int i=0;i<(1<<m);i++){
dp[i|arr[j]]=min(dp[i]+1,dp[i|arr[j]]);
if(dp[i|arr[j]]>0x3f3f3f3f){
dp[i|arr[j]]=inf;
}
}
}
cout<<(dp[(1<<m)-1]==inf?-1:dp[(1<<m)-1]);
return 0;
}
总结
蓝桥杯对于动态规划考察的还是比较深的,以后要多多复习一下动态规划了。