钱币组合加强版本+(两种方法)

Description

小明手上有 N!!!张纸币(他的钱很奇怪,可以是任意的正整数), 现在他想知道 用这N种纸币可以组合出多少种不同的总额出来。

Format

Input

第一行一个N.

第二行N个正整数,总和不超过10^8

N<=20

Output

如题

Samples

输入数据 1

5
1 1 2 3 4

输出数据 1

11

题解

有两种方法:

第一种:递归

我估计这种方法是每个读完题的人第一时间想到的方法了呵呵。

我们可以给每张钱币设两种状态:0是不取,1是取。然后我们开始递归:

#include<bits/stdc++.h>
using namespace std;
int n,a[21];
bool b[100000001];
void dfs(int id,int sum)   //id是我当前是第几张钱币,sum是当前钱的总和
{
    if(id==n+1)    //已经枚举完n张钱币了
    {
        b[sum]=1;    //标记一下当前总和
        return;
    }
    for(int i=0;i<=1;i++)
        dfs(id+1,sum+a[id]*i);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    dfs(1,0);
    int ans=0;
    for(int i=1;i<=100000001;i++)
    {
        if(b[i])ans++;
    }
    cout<<ans;
    return 0;
}

第二种:数学方法

我们可以发现:既然0是不取,1是取。这不就是二进制吗!

比如n是4,这4张钱币就有0000~1111这几种状态。1111是十进制的15,是2^4-1。

我们可以枚举i从1到2^n-1,每次将i转成二进制并放到数组里,将每一位乘a[i],最后记录总和sum就行了。

#include<bits/stdc++.h>
using namespace std;
int n,t,a[150000001];
bool b[150000001];
int c[150000001],u=0;
int main()
{
    cin>>n;
    t=(1<<n)-1;   //计算2^n-1
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int cnt=0;
    for(int i=1;i<=t;i++)
    {
        int t1=i;
        u=0;
        int j=i;
        while(j>0)
        {
            c[++u]=j%2;
            j/=2;
        }
        int sum=0;
        for(int j=u;j>=1;j--)
        {
            sum+=c[j]*a[j];   //计算总和sum
        }
        if(!b[sum])   //标记一下
        {
            b[sum]=1;
            cnt++;
        }
    }
    cout<<cnt;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值