部分和问题 题目:给定整数a1,a2,…,an,判断是否可以从中选出若干个数,使他们的和恰好为k。 限定条件:1<=n<=20, -10^8<=ai<=10^8, -10^8<=k<=10^8 输入:
4
1 2 4 7
13
4
1 2 4 7
15
输出:
Yes
No
//解法一:
这段代码是我根据01揹包的思想做的,我把问题看成是容量为k的揹包,有n件体积和价值都为a[i]的物品,求出揹包能装的最大价值,如果最大价值正好等于揹包容量,也就是说正好有体积相加为k的策略存在,证明这n个数中存在相加之和为k的策略。不过具体能不能AC我还没有测试。
感觉思路没问题,应该对O(∩_∩)O。
//代码(01揹包做法)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[25],n,k;
int dp[100000010];
int main()
{
while (scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&k);
for (int i=1;i<=n;i++)
for (int j=k;j>=a[i];j--)
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
if (dp[k]==k)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
//解法二:类似于构造一颗二叉树,i表示二叉树的层数,两支树叉分别表示加a[i]和不加a[i]的情况下sum的值。其实加与不加的策略很容易联想到01揹包中的装与不装的情况,所以用动规也能解决。
//代码:
#include<cstdio>
#include<cstring>
int a[25]={0},k,n;
//已经从前i项得到了和sum,然后对于i项之后的进行分支
//注意:第i+1项是a[i]。
bool dfs(int i,int sum)
{
if (i==n) //明明i是从0开始的为什么i==n结束,不应该是i==n-1吗?仔细想想,因为i==n-1时还没出界,还可以判断
return sum==k; //判断sum是否等于k,递归返回条件。(这里运用的是布尔类型,这里必须用‘==’)
if (dfs(i+1,sum)) //不加上a[i]的情况
return true; //在此dfs中如果sum==k成立时就返回true
if (dfs(i+1,sum+a[i])) //加上a[i]的情况
return true; //同样,在此dfs中如果sum==k成立时就返回true
return false; //无论加不加上a[i]都不能凑成k就返回false
}
void solve()
{
if (dfs(0,0))
printf("Yes\n");
else
printf("No\n");
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&k);
solve();
}
return 0;
}