蓝桥杯 2019 年省赛 A 组 I 题 糖果 洛谷P8687

文章介绍了如何通过动态规划求解一个关于糖果口味组合的问题,涉及状态转移方程和初始化过程。
摘要由CSDN通过智能技术生成

蓝桥杯 2019 年省赛 A 组 I 题

题目描述

糖果店的老板一共有 M M M 种口味的糖果出售。为了方便描述,我们将 M M M 种口味编号 1 1 1 M M M

小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K K K 颗一包整包出售。

幸好糖果包装上注明了其中 K K K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。

给定 N N N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

输入格式

第一行包含三个整数 N N N M M M K K K

接下来 N N N 行每行 K K K 这整数 T 1 , T 2 , ⋯   , T K T_1,T_2, \cdots ,T_K T1,T2,,TK,代表一包糖果的口味。

输出格式

一个整数表示答案。如果小明无法品尝所有口味,输出 − 1 -1 1

样例 #1

样例输入 #1

6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2

样例输出 #1

2

提示

对于 30 % 30\% 30% 的评测用例, 1 ≤ N ≤ 20 1 \le N \le 20 1N20

对于所有评测样例, 1 ≤ N ≤ 100 1 \le N \le 100 1N100 1 ≤ M ≤ 20 1 \le M \le 20 1M20 1 ≤ K ≤ 20 1 \le K \le 20 1K20 1 ≤ T i ≤ M 1 \le T_i \le M 1TiM

思路

1.DP下标及含义

DP[i]表示口味组合为i的二进制(若i为6即00110)情况下最少需要的糖果包数
在做输入的时候要注意状态的表示只能用或运算符,而不能用加,否则会导致相同的糖类重复计算

2.状态转移方程

F [ j ∣ a [ i ] ] = m i n ( F [ j ∣ a [ i ] ] , F [ j ] + 1 ) F[j|a[i]] = min(F[j|a[i]], F[j]+1) F[ja[i]]=min(F[ja[i]],F[j]+1)
当前口味组合加上a[i]包糖所含的口味组合,看是否能变小
如果F[j]+1更小,说明当前组合下有更优解

3.初始化

因为N最大值为100包,设置初始化DP数组均为105,表示无法尝到所有味道
F[0]为0,表示没有口味时,需要买0包糖
最终求的是 F [ 2 M − 1 ] F[2^M-1] F[2M1],即在 2 M − 1 2^M-1 2M1状态下最小糖果包数

4.遍历顺序

i: 0 − > N 0->N 0>N遍历所有糖果包
j: 0 − > 2 M − 1 0-> 2^M-1 0>2M1遍历所有组合

import java.util.Scanner;

public class Main {
   
    public static void main(String[] args) {
    	Scanner scan = new Scanner(System.in);
    	int N = scan.nextInt();
    	int M = scan.nextInt();
    	int K = scan.nextInt();
    	int[] candys = new int[105];
    	int[] dp = new int[1<<20+1];
    	for(int i=0;i<N;i++) {
    		for(int j=0;j<K;j++) {
    			int t = scan.nextInt();
    			candys[i] = candys[i]|1<<(t-1);
    		}
    	}
    	for(int i=0;i<1<<20;i++) {
    		dp[i] = 105;
    	}
    	dp[0] = 0;
    	for(int i=0;i<N;i++) {
    		for(int j=0;j<1<<M;j++) {
    			int temp = Math.min(dp[j|candys[i]], dp[j]+1);
//    			System.out.println(temp);
    			dp[j|candys[i]] = temp;
    		}
    	}
    	int ans = dp[(1<<M)-1]==105? -1:dp[(1<<M)-1];
    	System.out.print(ans);
    }
}

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值