例题一:
给你一个非负整数数组 nums
和一个整数 target
。
向数组中的每个整数前添加 '+'
或 '-'
,然后串联起所有整数,可以构造一个 表达式 :
- 例如,
nums = [2, 1]
,可以在2
之前添加'+'
,在1
之前添加'-'
,然后串联起来得到表达式"+2-1"
。
返回可以通过上述方法构造的、运算结果等于 target
的不同 表达式 的数目。
示例 1:
输入:nums = [1,1,1,1,1], target = 3 输出:5 解释:一共有 5 种方法让最终目标和为 3 。 -1 + 1 + 1 + 1 + 1 = 3 +1 - 1 + 1 + 1 + 1 = 3 +1 + 1 - 1 + 1 + 1 = 3 +1 + 1 + 1 - 1 + 1 = 3 +1 + 1 + 1 + 1 - 1 = 3
示例 2:
输入:nums = [1], target = 1 输出:1
代码:
class Solution {
int f[25][3010];
public:
int findTargetSumWays(vector<int>& nums, int target) {
if(target<0)target=-target;
int sum=0;
int length=nums.size();
for(int i=0;i<length;++i){
sum+=nums[i];
}
if(target>sum)return 0;
f[0][sum]=1;
for(int i=1;i<=length;++i){
for(int j=0;j<=sum;++j){
f[i][j]=f[i-1][j+2*nums[i-1]]+f[i-1][j];
}
}
return f[length][target];
}
};
解题思路:
先将target转化为整数,然后求出非负数数组的和,将其与target比较,如果target较大,则本题无解,直接结束;若小于,则进行以下计算。先定义一个二维数组f[i][j],i表示前i个数,j表示所得到的和,f[i][j]表示i个数加上符号后表示j的方法数。之后来求状态转移方程,f[i][j]=max(f(i-1,j+2nums[i-1]),f[i-1][j]),其中前一个表示给当前这个数加上负号,所以对应的j要增大,后者表示当前这个数不加负号。注意,这里j要限制在小于sum而不是小于target,否则j+2nums[i-1]可能会越界.
例题二:
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n标号。为了在门口展出更多种花,规定第 i 种花不能超过 ai 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入格式
第一行包含两个正整数 n 和 m,中间用一个空格隔开。
第二行有 n 个整数,每两个整数之间用一个空格隔开,依次表示 a1,a2,⋯,an。
输出格式
一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对 10^6+7 取模的结果。
代码:#include<bits/stdc++.h>
using namespace std;
const int mod=1000007;
int n,m,a[100];
int dp[105];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=m;j>=0;j--){
for(int k=1;k<=min(a[i],j);k++){
dp[j]=(dp[j]+dp[j-k])%mod;
}
}
}
cout<<dp[m]<<endl;
return 0;
}
解题思路:
定义数组dp[i],循环中第一层表示花的种类,第二层遍历摆放花的盆数,第三层记录依次记录摆放花的盆数对应的方法数。第三层循环的上线由摆放花的盆书和此时摆放的这种花的盆书的最小值决定。依次叠加时,记得要对答案取模。