[递归,动态规划] 和为定值的子集合

和为定值的子集数

题目描述

已知 n 个正整数,wi  (1≤i≤n) 形成一个集合 W={w1,w2,...,wn},集合中的元素彼此不相同。给定某个正整数 M ,集合W中可否存在子集,该子集的所有元素之和和恰好为M,问:这样的子集有多少个?
例如,4个正整数为:
11 13 24 7
若给定M=31,则有两个子集{7,11,13}和{7,24}
于是,这样的子集有 2 个。

关于输入

第1行,输入若干个正整数,表示集合的元素,各整数之间以空格间隔;
后面有多行,每行表示一个 M 值;若某行的 M 值为0,则结束。

关于输出

对应的每个有效的 M 值,输出相应行的子集数目

例子输入
11 13 24 7
31
24
45
55
0
例子输出
2
2
0
1
解题分析

这个问题可以使用动态规划(Dynamic Programming)来解决。动态规划是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

在这个问题中,我们需要找到所有和为特定值 M 的子集的数量。我们可以使用一个二维动态规划数组 dp[i][j] 来存储到第 i 个元素为止,和为 j 的子集的数量。

这个问题的状态转移方程可以这样定义:

1. 如果当前集合的总和 M 为0,那么只有一个子集满足条件,即空子集,所以返回1。
2. 如果我们已经查看过所有的元素(i < 0),或者当前的总和 M 为负数,那么没有子集满足条件,返回0。
3. 如果当前元素 a[i] 大于当前的总和 M,那么我们不能包含这个元素,所以只能查看前 i-1 个元素,看看他们能否组成和为 M 的子集。所以 dp[i][M] = sum(i-1, M)。
4. 如果当前元素 a[i] 小于或等于当前的总和 M,那么我们有两种选择:包含这个元素或者不包含这个元素。所以 dp[i][M] = sum(i-1, M) + sum(i-1, M-a[i])。

在主函数中,我们首先使用一个循环来读取输入的元素,并将它们存储在数组 a 中。然后,我们使用另一个循环来读取输入的 M 值,并调用 sum 函数来计算满足条件的子集的数量。最后,我们将结果输出到屏幕上。

注意,为了提高效率,我们使用了记忆化搜索(也称为缓存)。我们使用一个二维数组 dp 来存储已经计算过的子问题的结果。在 sum 函数中,我们首先检查 dp[i][M] 是否已经被计算过。如果是,我们就直接返回它。否则,我们就计算它,然后将结果存储在 dp[i][M] 中,以便以后使用。

这种方法的时间复杂度是 O(n*M),其中 n 是集合的元素数量,M 是目标和。空间复杂度也是 O(n*M),用于存储 dp 数组。

代码实现
#include <iostream>
#include <cstring>
using namespace std;

int M, a[10000];
int len = 0;
int dp[10000][10000]={0};

int sum(int i, int M) {
    if (M == 0) return 1;
    if (i < 0 || M < 0) return 0;
    if(dp[i][M]!=-1) return dp[i][M];
    if (a[i] > M) {
        dp[i][M]=sum(i-1,M);
        return dp[i][M];
    } else {
        dp[i][M]=sum(i - 1, M) + sum(i - 1, M - a[i]);
        return dp[i][M];
    }
}

int main() {
    char c;
    memset(dp,-1,sizeof(dp));
    while (cin >> a[len++]) {
        c = getchar();
        if (c == '\n') break;
    }
    while (cin >> M) {
        if (M == 0) break;
        cout << sum(len - 1, M) << endl;
    }
    return 0;
}

方法2:

解题分析2

这个问题可以使用动态规划来解决。我们可以构建一个二维数组dp,其中dp[i][j]表示使用前i个数字组成和为j的子集的数量。

初始条件是dp[i][0] = 1,表示使用前i个数字组成和为0的子集只有一种可能,即一个空集。然后我们可以根据以下状态转移方程来填充dp数组:

dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]], 如果 j >= nums[i - 1]
dp[i][j] = dp[i - 1][j], 如果 j < nums[i - 1]

其中nums[i - 1]表示第i个数字。第一个条件表示我们可以选择包含第i个数字或者不包含第i个数字,第二个条件表示如果当前的和j小于第i个数字,那么我们不能选择第i个数字。

这个算法的时间复杂度是O(n * M),空间复杂度也是O(n * M),其中n是集合中的数字数量,M是给定的目标和。

#include <iostream>
#include <cstring>
using namespace std;

int M, a[10000];
int len = 0;
int dp[10000][10000]={0};

int main() {
    char c;
    while (cin >> a[len++]) {
        c = getchar();
        if (c == '\n') break;
    }
    while (cin >> M) {
        if (M == 0) break;
        for(int i=0;i<len;i++){
            dp[i][0]=1;
        }
        for(int i=0;i<len;i++){
            for(int j=1;j<=M;j++){
                if(i==0){
                    if(a[i]==j){
                        dp[i][j]=1;
                    }
                    continue;
                }
                if(a[i]>j){
                    dp[i][j]=dp[i-1][j];
                }
                else{
                    dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]];
                }
            }
        }
        cout<<dp[len-1][M]<<endl;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/189407.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

图片处理工具JixiPix Pastello mac中文版功能特色

JixiPix Pastello mac是一款数字绘画软件&#xff0c;它可以将照片转换为仿佛是手绘的油画、粉笔画、素描等风格的艺术作品。该软件提供了多种绘画效果和工具&#xff0c;例如颜料、画笔、纸张等&#xff0c;让用户可以轻松地调整画作的亮度、色彩和细节等参数&#xff0c;从而…

java_基础_关键字

1.关键字的字母全部都是小写. 2.常用的代码编辑器(Notepad),针对关键字有特殊的颜色标记,非常的直观.

【anaconda】numpy.dot 向量点乘小技巧

假设向量A[1,1], 向量B[2,3]。如果想知道他们的内积就可以输入如下代码: 当然&#xff0c;如果是两个列向量相乘&#xff0c;肯定是不对的 但是如果没有维度也一样可以求得内积&#xff0c;而且结果不会套在列表里

IO和NIO的区别 BIO,NIO,AIO 有什么区别? Files的常用方法都有哪些?

文章目录 IO和NIO的区别BIO,NIO,AIO 有什么区别?Files的常用方法都有哪些&#xff1f; 今天来对java中的io, nio, bio, aio进行了解&#xff0c;有何区别。 IO和NIO的区别 NIO与IO区别 IO是面向流的&#xff0c;NIO是面向缓冲区的Java IO面向流意味着每次从流中读一个或多个字…

SSF-CNN:空间光谱融合的卷积光谱图像超分网络

SSF-CNN: SPATIAL AND SPECTRAL FUSION WITH CNN FOR HYPERSPECTRAL IMAGE SUPER-RESOLUTION 文章目录 SSF-CNN: SPATIAL AND SPECTRAL FUSION WITH CNN FOR HYPERSPECTRAL IMAGE SUPER-RESOLUTION简介解决问题网络框架代码实现训练部分运行结果 简介 ​ 本文提出了一种利用空…

YOLOv5轻量化改进之MobileNetv3

目录 一、原理 二、代码 三、应用到YOLOv5 一、原理 我们提出了基于互补搜索技术和新颖架构设计相结合的下一代mobilenet。MobileNetV3通过硬件网络架构搜索(NAS)和NetAdapt算法的结合来调整到移动电话cpu,然后通过新的架构进步进行改进。本文开始探索自动搜索算法和网络设计…

5 个适用于 Windows 的顶级免费数据恢复软件

对于计算机来说&#xff0c;最重要的是用户数据。除了您的数据之外&#xff0c;有关计算机的其他所有内容都是可替换的。这三个是数据丢失的最常见原因&#xff1a; 文件/文件夹删除丢失分区分区损坏 文件/文件夹删除 文件/文件夹删除是最常见的数据丢失类型。大多数时候&am…

Matplotlib网格子图_Python数据分析与可视化

Matplotlib网格子图 plt.subplot()绘制子图调整子图之间的间隔plt.subplots创建网格 plt.subplot()绘制子图 若干彼此对齐的行列子图是常见的可视化任务&#xff0c;matplotlib拥有一些可以轻松创建它们的简便方法。最底层且最常用的方法是plt.subplot()。 这个函数在一个网格…

零基础学Linux内核:1、Linux源码组织架构

文章目录 前言一、Linux内核的特征二、Linux操作系统结构1.Linux在系统中的位置2.Linux内核的主要子系统3、Linux系统主要数据结构 三、linux内核源码组织1、下载Linux源码2、Linux版本号3、linux源码架构目录讲解 前言 这里将是我们从零开始学习Linux的第一节&#xff0c;这节…

【Kotlin】类与接口

文章目录 类的定义创建类的实例构造函数主构造函数次构造函数init语句块 数据类的定义数据类定义了componentN方法 继承AnyAny&#xff1a;非空类型的根类型Any?&#xff1a;所有类型的根类型 覆盖方法覆盖属性覆盖 抽象类接口:使用interface关键字函数&#xff1a;funUnit:让…

C++ 通过SQLite实现命令行工具

本文介绍了一个基于 C、SQLite 和 Boost 库的简单交互式数据库操作 Shell。该 Shell 允许用户通过命令行输入执行各种数据库操作&#xff0c;包括添加、删除主机信息&#xff0c;设置主机到特定主机组&#xff0c;以及显示主机和主机组列表。通过调用 SQLite3 库实现数据库连接…

适用于 Mac 和 Windows 的顶级U 盘数据恢复软件

由于意外删除或设备故障而丢失 USB 驱动器中的数据始终是一件令人压力很大的事情&#xff0c;检索该信息的最佳选择是使用优质数据恢复软件。为了让事情变得更容易&#xff0c;我们已经为您完成了所有研究并测试了工具&#xff0c;并且我们列出了最好的 USB 记忆棒恢复软件&…

elasticsearc DSL查询文档

文章目录 DSL查询文档DSL查询分类全文检索查询使用场景基本语法示例 精准查询term查询range查询总结 地理坐标查询矩形范围查询附近查询 复合查询相关性算分算分函数查询1&#xff09;语法说明2&#xff09;示例3&#xff09;小结 布尔查询1&#xff09;语法示例&#xff1a;2&…

基于C#实现Kruskal算法

这篇我们看看第二种生成树的 Kruskal 算法&#xff0c;这个算法的魅力在于我们可以打一下算法和数据结构的组合拳&#xff0c;很有意思的。 一、思想 若存在 M{0,1,2,3,4,5}这样 6 个节点&#xff0c;我们知道 Prim 算法构建生成树是从”顶点”这个角度来思考的&#xff0c;然…

车载电子电器架构 ——电子电气架构设计方案概述

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 注:本文1万多字,认证码字,认真看!!! 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证…

机器学习探索计划——KNN算法流程的简易了解

文章目录 数据准备阶段KNN预测的过程1.计算新样本与已知样本点的距离2.按照举例排序3.确定k值4.距离最近的k个点投票 scikit-learn中的KNN算法 数据准备阶段 import matplotlib.pyplot as plt import numpy as np# 样本特征 data_X [[0.5, 2],[1.8, 3],[3.9, 1],[4.7, 4],[6.…

FreeRTOS入门教程(任务通知)

文章目录 前言一、什么是任务通知二、任务通知和队列&#xff0c;信号量的区别三、任务通知的优点和缺点1.优点2.缺点 四、任务状态和通知值五、任务通知相关的函数发出通知取出通知 六、任务通知具体使用1.实现轻量级信号量二进制信号量计数型信号量 2.实现轻量级队列 总结 前…

数仓中数据清洗的方法

在数据采集的过程中&#xff0c;需要从不同渠道获取数据并汇集在数仓中&#xff0c;采集的原始数据首先需要进行解析&#xff0c;然后对不准确、不完整、不合理、格式、字符等不规范数据进行过滤清洗&#xff0c;清洗过的数据才能更加符合需求&#xff0c;从而使后续的数据分析…

【数据库】执行计划中二元操作对一趟扫描算法的应用,理解代价评估的应用和优化,除了磁盘代价还有CPU计算代价不容忽略

二元操作的一趟算法 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定…

Java中的异常语法知识居然这么好玩!后悔没有早点学习

学习异常后&#xff0c;发现异常的知识是多么的吸引人&#xff01;不仅可以用来标记错误&#xff0c;还可以自己定义一个异常&#xff0c;用来实现自己想完成的业务逻辑&#xff0c;接下来一起去学习吧 目录 一、异常的概念及体系结构 1.异常的概念 2.异常的体系结构 3.异常…