IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 状态压缩+动态规划(蓝桥杯2019 java A组 糖果问题) -> 正文阅读

[数据结构与算法]状态压缩+动态规划(蓝桥杯2019 java A组 糖果问题)

前言

看到这个标题,说明我还是无知了,算法小白报道。
首先之所以会有这个问题是因为,这样一道题目

糖果 时间限制: 1.0s 内存限制: 256.0MB 本题总分:25分

【问题描述】 ??糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1 ~ M。
??小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。 ??幸好糖果包装上注明了其中 K
颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。 ??给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

【输入格式】 ??第一行包含三个整数 N、M 和 K。接下来 N 行,每行 K 个整数 T1, T2, · · · ,
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 。

思路

当时呢,我的第一个想法是类似于一个启发式的一个算法,使用“支配”的想法,想去解决这个问题,但是这个状态不好表示,写出来之后应该是一个递归,不过复杂度的话和dp应该不会差太多,但是那个不好搞。

Dp 思想

那么到这里的话,我们自然就能先联想到背包问题,想到dp。
题目的要求自然就是,说,想要吃到所以糖果的包数嘛(最小包数)。
所以很容易想到一个dp数组 dp[i][j] 在i包下,j 状态下(这个状态是指现在吃到了多少种糖果)。
然后这个 d[i][j] = value 按照这个意思这个value 就是i嘛,这样自然就直接实现了将维,那么此时我们构建的dp是指这样的dp[i]=j 表示在i状态下,需要j包糖果。
在这里插入图片描述

DP方程

我们先来说说这个dp的策略
如果 当前的状态(例如当前表示吃到了4种) 上一种状态是吃到了三种,然后是拿了1包
这里就看情况了,
如果,当前的这个状态在我们原来的dp数组里面保存的状态是没有的,那么自然我们就直接
在上一个状态的基础上拿下这一包就行了
如果有,并且在这种情况下是拿了3包,那么显然此时的这个状态对应的包数也是应该是上一个状态拿到的包数+1

具体的看代码
在这里插入图片描述

如何保存状态

二进制状态保存

前面我们假设了这么多,问题来了我们这个状态怎么表示呀?
这里就是传说当中的状态压缩了,如何直接把一组状态变成一个数字呢?

这里就需要使用到神奇的二进制了。
怎么做呢,例如这组数据
1 1 2
由于我们有5种口味嘛,所以可以这样
我们的二进制是这样的格式 00000
第一个数字过来变成了这样
00001
第二个数字过来,我们 | 取或运算所以还是
00001
接下来第三个
00011

此时我们再转化为十进制于是得到了 3
此时这个三就是表示了我们状态

6 5 3    状态压缩
		二进制  十进制
1 1 2   00011	3
1 2 3	00111	7
1 1 3	00101	5


编码

接下来编码解决问题

class Main{
    private static int N;
    private static int M;
    private static int K;
    static boolean[][] vis = new boolean[105][22];
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();// 多少包糖
        M = sc.nextInt();// 几种口味
        K = sc.nextInt();// 每包糖多少口味
        int[] w = new int[N+1];
        int[] dp=new int[1<<20];
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < K; j++) {
                int k = sc.nextInt();
                w[i] |=(1<<k-1) ;
                //存储每一包的状态,但是这个第一个数第一个状态不能改变,所以需要把k-1
                
                //这个的牛逼之处就是把一串状态数组,转化二进制(运算),之后变回十进制表示为一个数字表示状态
            }
        }
        Arrays.fill(dp, -1);//初始化-1,
        dp[0]=0;
        //dp的方程含义是下一个状态
        for(int i = 1;i<=N;i++)
            
            for(int s = 0;s < (1 << M);s++) {
                if (dp[s] == -1) continue;
                int nst = s | w[i];//下一个状态,比上一个状态多吃到一种糖果的状态(多吃一包)
                if (dp[nst] == -1 || dp[nst] > dp[s] + 1) dp[nst] = dp[s] + 1;
                //如果没有状态那么自然-1,如果有这个状态,并且这个状态不如上一个状态多吃一个那么就舍弃,直接上一个状态+1
            }
        System.out.println(dp[(1<<M)]);

    }

}

总结

我是菜鸡…

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:50:47  更:2022-03-10 22:55:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:27:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码