#include<iostream>
#include<cmath>
using namespace std;
/**
判断一个正数 数组中的数是否可以组合起来 为一个给定的值 如果可以返回true
*/
const int N=1010;
int a[N];
int dp[N][100];
//递归解法 从小标0开始到达i 判断是否可以有构成和为的s数
bool fun(int i,int s){
if(s==0) return true;
else if(i==0)//到达第一个
return a[0]==s;//如果第0个刚好等于s 则返回true 不行则返回false
else if(a[i]>s)//下标为i a[i]已经大于s 则不选
return fun(i-1,s);
else{
//判断选与不选a[i]
bool t1=fun(i-1,s-a[i]);//这是选择了a[i]
bool t2=fun(i-1,s);//不选
return t1||t2;
}
}
//非递归解法 构建一个二维数组 dp[i][s] 表示从0到达i的时候 能否构建成和为s的真假值
void fun2(int n,int s){
for(int j=0;j<=s;j++)
{
dp[0][j]=0;
}
//比如第0个的值为3 因为我们的dp[0][3] 表示从0到0是否可以组成3 所以dp[0][3] 直接为true
if(a[0]<=s)//当第0个已经比s要大 则显然无法来构建s 只能是小于s的时候
dp[0][a[0]]=1;
for(int i=0;i<n;i++)
dp[i][0]=1;//当dp[i][j] 即要给定的值为0时 表示无需其他值来构建了 目前已完成则就是true了
//a[i][j] 表示从a[0] 到a[i] 是否可以组成j 的真假值
//i从a[0]-a[n-1] j从0到给定值s
for(int i=1;i<n;i++){
for(int j=1;j<=s;j++){
if(a[i]>j)// a[i] 已经比j还要大了,很显然这个时候不选则a[i]
dp[i][j]=dp[i-1][s];
else{
int t3= dp[i-1][j-a[i]];//选择了a[i]
int t4=dp[i-1][j];//不选a[i]
dp[i][j]=(t3||t4);
}
}
}
}
int main(void){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i];
// if(fun(n-1,m))
// cout<<"true"<<endl;
// else
// cout<<"false"<<endl;
fun2(n,m);
if(dp[n-1][m])
cout<<"true"<<endl;
else
cout<<"false"<<endl;
}
其中非递归的方式可以借助以下这张图来理解

这篇博客探讨了如何运用动态规划算法判断一个数组中是否能找出子集,其元素之和等于给定的目标数值。通过非递归的方法,借助图表辅助理解,详细解析了动态规划的解题思路。
5万+

被折叠的 条评论
为什么被折叠?



