时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种 口味编号 1 ∼ M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而 是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知 道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖 果。
【输入格式】
第一行包含三个整数 N、M 和 K。接下来 N 行每行 K 这整数 T1, T2, · · · , T**K,代表一包糖果的口味。
【输出格式】
一个整数表示答案。如果小明无法品尝所有口味,输出 −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≤T**i ≤M。
思路:(没学过状态压缩的小伙伴可以离开了qwq)
这道题很明显是用状态压缩动态规划(蒟蒻刚开始做的时候居然想用并查集,后面才发现自己的算法内功还不够)。我们将每一行的糖果的状态存储下来,比如第一组数据1 1 2,我们记录成00011(假如只有五个二进制数),第二组数据1 2 3记录成00111。然后就是常规的动态规划思想了。下面直接上代码(带详细注释):
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//n包糖果
int m=sc.nextInt();//一共有m种口味
int k=sc.nextInt();//一包糖果中有K颗糖果
int[] w = new int[n+1];//用w记录每一包糖果包含的所有口味
int[] dp = new int[1<<20];//状态压缩dp
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
int temp=sc.nextInt();
w[i]|=(1<<temp-1);
}//例如,第二包糖果1 2 3,那么001|010|100 = 011|100 = 111
}
Arrays.fill(dp,21);//因为m<=20,求得是min,所以我们把初始值设为21
for(int i=1;i<=n;i++){
dp[w[i]]=1;//这里我们将每一行的情况设为1,即最少情况为买一包
for(int j=0;j<(1<<m);j++){
int z=j|w[i];//比如01100|00001=01101,两种情况相加
dp[z]=Math.min(dp[z],dp[j]+1);//经典线性?
}
}
//这里注意,如果(1<<m)-1的情况最少需要买21包,那说明买完20包,也买不到所有口味,输出-1
System.out.println(dp[(1<<m)-1]<=20?dp[(1<<m)-1]:-1);
}
}