完全背包(SOJ 2785)

SOJ 2785: http://acm.scu.edu.cn/soj/problem.action?id=2785

题意:任意一个正整数都可以分解成2的幂次数之和,这里2的幂次数为集合{1,2,4,8,16,32,...}. 举个例子5,

5=1+1+1+1+1

5=1+1+1+2

5=1+2+2

5=1+4

现在给定一个数n,求解上述的分解方式有多少种。

方法一

经过分析这道题是一个完全背包问题。具体来说,将n当做背包的容量,S={1,2,4,8,16,32,...}中的每个数当做物品并且每个物品可以取任意次。定义dp[i][j]为数j由集合中的前i个数组成的方式数目,那么状态转移方程为

dp[i][j]=dp[i][j-S[i]]+dp[i-1][j].

注意初始条件为dp[0]=1. n给定了范围,所以我们可以打一个表,把所有情况计算出来。代码如下:

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int dp[2000005];
int main()
{
    int T,n;
    scanf("%d", &T);
    int i,j;
    int con = 1000000;
    memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    for (i = 1; i <= 2000000; i <<= 1)
        for (j = i; j <= 2000000; j++)
            dp[j] = (dp[j] + dp[j - i]) % con;
    while (T--)
    {
        scanf("%d", &n);
        printf("%d\n", dp[n]);
    }
    return 0;
}
View Code

方法二

看到这道题直觉上感觉是个组合数学题,应该有一个递推公式。定义f(n)为n的种类数,当n为偶数的时候,

f(n)=f(n-1)+f(n/2).

f(n)由两部分组成,一部分含有1,另一部分不含1(都是偶数且为2的次幂)。不含1的这部分跟f(n/2)是一一对应的,含有1的这部分跟f(n-1)是一一对应的。证明方式可以通过下面的定理:

若a≤b并且b≤a, 则a=b. 

n为偶数时,f(n)=f(n+1). 证明思路相同,需要注意一点的是f(n+1)中所有情况都含有1(因为n+1是奇数)。

posted on 2019-03-05 14:21  小叶子曰  阅读(160)  评论(0编辑  收藏  举报

导航