动态规划:部分和问题和数字和为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是整型,在实际操作中根据自己需要的类型转换.
随机推荐
- [linux]linux下安装mysql
1.安装g++$sudo apt-get install build-essential注:此命令会同时安装gcc和make2.安装cmake$sudo apt-get install cmake3. ...
- [php]HTTP协议头解析
(Request-Line) GET /static/imgs/bqpd.jpg HTTP/1.1 Accept image/png, image/svg+xml, image/*;q=0.8, */ ...
- 2016-2017-2 20155117实验二《Java面向对象程序设计》实验报告
实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 1.参考Intellj IDEA 简易教程 提交 ...
- C.Fountains(Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)+线段树+RMQ)
题目链接:http://codeforces.com/contest/799/problem/C 题目: 题意: 给你n种喷泉的价格和漂亮值,这n种喷泉题目指定用钻石或现金支付(分别用D和C表示),C ...
- JS设计模式——3.封装与信息隐藏
封装.信息隐藏与接口的关系 信息隐藏是目的,封装是手段. 接口提供了一份记载着可供公共访问的方法的契约.它定义了两个对象间可以具有的关系.只要接口不变,这个关系的双方都是可以替换的. 一个理想的软件系 ...
- Fiddler -工具使用介绍(附:拦截请求并修改返回数据)(转)
一.Fiddler 介绍 Fiddler 是一个使用 C# 编写的 http 抓包工具.它使用灵活,功能强大,支持众多的 http 调试任务,是 web.移动应用的开发调试利器. 1,功能特点 同 H ...
- 不相交集ADT--链表实现
每一个集合用用一个链表来表示.链表的第一个对象作为它所在集合的代表.链表中每个对象都包含一个集合成员,一个指向下一个对象的指针,以及指向代表的指针.每个链表含head和tail指针,head指向链表的 ...
- python 协程嵌套
import asyncio import time now = lambda: time.time() async def do_some_work(x): print('Waiting: ', x ...
- 设计模式之笔记--职责链模式(Chain of Responsibility)
职责链模式(Chain of Responsibility) 定义 职责链模式(Chain of Responsibility),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系 ...
- 详解Oracle的unlimited tablespace系统权限
1. 系统权限unlimited tablespace是隐含在dba, resource角色中的一个系统权限. 当用户得到dba或resource的角色时, unlimited tablespace系 ...