部分和问题

来源:互联网 发布:重庆大学网络网上报修 编辑:程序博客网 时间:2024/06/05 03:13
部分和问题
题目:给定整数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;}



0 0
原创粉丝点击