动态规划:部分和问题和数字和为sum的方法数
很久之前看过这个题目,但是没有仔细整理,直到现在看基础才想到这两个题。这两个题非常经典也非常类似。接下来分别介绍。
部分和问题
题目描述
给定整数a1、a2、.......an,判断是否可以从中选出若干数,使它们的和恰好为K。
输入
首先,n和k,n表示数的个数,k表示数的和。
接着一行n个数。
(1<=n<=20,保证不超int范围)
输出
如果和恰好可以为k,输出“YES”,并按输入顺序依次输出是由哪几个数的和组成,否则“NO”
样例输入
4 13
1 2 4 7
样例输出
YES
2 4 7
思路:
很明显,这是一道简单的dfs搜索,直接理由dfs的定义解决,不过最难点是如何实现剪枝,减少不必要的时间浪费,这道题需要减掉的是
1.从当前状态如何转移都不会存在解
2.当sum超过k时,也没必要继续搜索
代码:
//没有剪枝的代码
#include<cstdio>
#include<iostream>
using namespace std;
int n,k,a[],b[];
bool dfs(int x,int sum) //从左到右遍历一遍可得解
{
if(sum>k)
return false;
if(x==n)
return sum==k; //如果前n项计算过了,返回sum=k是否相等
if(dfs(x+,sum))
{
b[x]=; //如果不加上a[x]的情况,标记为0;
return true;
}
if(dfs(x+,sum+a[x]))
{
b[x]=; //如果加上a[x]的情况,标记为1;
return true;
}
return false;
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i = ; i<n; i++)
scanf("%d",&a[i]);
if(dfs(,))
{
printf("YES\n");
for(int i=; i<n; i++)
if(b[i])
printf("%d ",a[i]);
printf("\n");
}
else
printf("NO\n");
}
return ;
}
和为sum的方法数
题目描述:
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
输入:
输入为两行:
第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行为n个正整数A[i](32位整数),以空格隔开。
输出:
输出所求的方案数
样例输入
5 15
5 5 10 2 3
样例输出
4
思路一:
用递归加回溯的方法,找出数组的所有子集。
若子集和等于整数sum,则数组A中部分数字和为sum的方案数加一。
可优化的地方在子集当前和大于sum,则跳出该分支,因为数组A为正整数,之后的子集和只会越来越大。
这种方法缺点在于:时间复杂度大,为 O(2 ^ n) ,递归调用次数过多,容易爆栈。
#include<iostream>
#include<vector>
using namespace std;
int n, sum, count = ; void help(vector<int>& a, int pos, int part) { if (part == sum)
count++; if (part > sum)
return; for(int i=pos; i<n; i++) {
part += a[i];
help(a, i+, part);
part -= a[i];
}
} int main(){
cin>>n>>sum; vector<int> a(n);
for(int i=; i<n; i++)
cin>>a[i]; help(a, , ); cout<<count<<endl; return ; }
思路二:
用动态规划,类似01背包问题,f(i , j )表示前i 个数中和为 j 的方案数, 则 若 j >= a[i], f ( i ,j) = f(i -1, j)+ f (i - 1,j - a[i] );
否则, f ( i ,j) = f(i -1, j)。
可优化地方:由于二维数组中,第i行 只与第 i - 1 行有关,所有我们若从 最后一列 开始更新数组,则可用一维数组来保存先前状态。
时间复杂度为:O( n * sum ) 。
#include<iostream>
#include<vector>
using namespace std; int main() {
int n, sum;
cin>>n>>sum; vector<long long> a(sum+);
vector<int> b(n); for(int i=; i<n; i++)
cin>>b[i]; a[] = ; for (int i=; i<n; i++)
for (int j=sum; j>=b[i]; j--)
a[j] += a[j-b[i]]; cout<<a[sum]<<endl; return ; }
动态规划:部分和问题和数字和为sum的方法数的更多相关文章
- 数字和为sum的方法数
[编程题] 数字和为sum的方法数 给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数. 当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案. 输入描 ...
- 数字和为sum的方法数(动态规划)
题目描述 给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数.当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案. 输入描述: 输入为两行: 第一行为 ...
- 动态规划:数字和为sum的方法数
题目描述 给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数.当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案. 输入描述: 输入为两行: 第一行为 ...
- Problem C: 动态规划基础题目之数字三角形
Problem C: 动态规划基础题目之数字三角形 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 208 Solved: 139[Submit][Sta ...
- Leetcode之深度优先搜索(DFS)专题-129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers)
Leetcode之深度优先搜索(DFS)专题-129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers) 深度优先搜索的解题详细介绍,点击 给定一个二叉树,它的每个结点都存放 ...
- 【动态规划】Vijos P1218 数字游戏(NOIP2003普及组)
题目链接: https://vijos.org/p/1218 题目大意: 一个N个数的环,分成M块,块内的数求和%10,最后每块地值累乘,求最大和最小. n(1≤n≤50)和m(1≤m≤9)太小了可以 ...
- 数字组合 · Combination Sum
不能重复: [抄题]: 给出一个候选数字的set(C)和目标数字(T),找到C中所有的组合,使找出的数字和为T.C中的数字可以无限制重复被选取. 例如,给出候选数组[2,3,6,7]和目标数字7,所求 ...
- LeetCode 129. 求根到叶子节点数字之和(Sum Root to Leaf Numbers)
题目描述 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字. 例如,从根到叶子节点路径 1->2->3 代表数字 123. 计算从根到叶子节点 ...
- sqlserver可将字符转成数字再进行sum,如果varchar类型中存放的都是数字
sqlserver语法: select sum(cast(score as int)) as score from 表名; 注意:int是整型,在实际操作中根据自己需要的类型转换.
随机推荐
- 【CodeForces】679 A. Bear and Prime 100
[题目]A. Bear and Prime 100 [题意]有一数字x,每次可询问一个数字y是否x的因子,最后输出数字x是否素数,要求询问次数<=20. [题解]容易发现[2,100]范围内的非 ...
- Spring Session加Redis
session是一个非常常见的概念.session的作用是为了辅助http协议,因为http是本身是一个无状态协议.为了记录用户的状态,session机制就应运而生了.同时session也是一个非常老 ...
- css3同心圆闪烁扩散效果
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Oracle笔记之表空间
Oracle中有一个表空间的概念,一个数据库可以有好几个表空间,表放在表空间下. 1. 创建表空间 创建表空间使用create tablespace命令: CREATE TABLESPACE foo_ ...
- 使用OpenCV和Python进行人脸识别
介绍 人脸识别是什么?或识别是什么?当你看到一个苹果时,你的大脑会立刻告诉你这是一个苹果.在这个过程中,你的大脑告诉你这是一个苹果水果,用简单的语言来说就是识别.那么什么是人脸识别呢?我肯定你猜对了. ...
- linux学习记录.1.安装
最近想了想决定开始学习linux. 在百度了一番后开始了安装,虚拟机VirtualBox,ubuntu. 基于VirtualBox虚拟机安装Ubuntu图文教程: http://blog.csdn.n ...
- 33 - 并发编程-线程同步-Event-lock
目录 1 线程同步 1.1 Event 1.1.1 什么是Flag? 1.1.2 Event原理 1.1.3 吃包子 1.2 Lock 1.2.1 lock方法 1.2.2 计数器 1.2.3 非阻塞 ...
- MySQL创建相同表和数据命令
创建和表departments结构和数据一样的表departments_t mysql> create table departments_t like departments; Query O ...
- Oracle常用sql语句(二)之组函数、多表查询
DML(数据操纵语言) INSERT .UPDATE. DELETE 插入操作:INSERT: 语法: INSERT INTO 表名(列名1,列名2 ...)VALUES(列值1,列值2...); 注 ...
- SQL:select case when 的用法
CASE 可能是 SQL 中被误用最多的关键字之一.虽然你可能以前用过这个关键字来创建字段,但是它还具有更多用法.例如,你可以在 WHERE 子句中使用 CASE. 首先让我们看一下 CASE 的语法 ...