Sumsets POJ - 2229 (完全背包变形 || 简单dp)

Sumsets POJ - 2229 (完全背包变形 || 简单dp)

题目链接
题目大意:求把一个整数分解为2的幂的和共有几种方案
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+2+2
7=1+1+1+4
7=1+2+2+2
7=1+2+4
输出6
思路:一开始的时候推过,没推出来。后来看了一眼题解,说是完全背包的变形,顿悟。可还是没想出来怎么变形。看代码吧。

#include 
#include 
#include 
#include 
using namespace std;

#define MOD 1000000000
int dp[1000001], data[30];

int main()
{
    data[0] = 1;
    for(int i = 1; ; i++) {
        if(data[i - 1] * 2 > 1000000) break;
        data[i] = data[i - 1] * 2;
    }
    int n;
    while(~scanf("%d", &n))
    {
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for(int i = 0; i <= 19; i++)
        {
            for(int j = data[i]; j <= n; j++)
            {
                dp[j] = (dp[j] + dp[j - data[i]]) % MOD;
                //主要是这里没有想出来 其实这里的dp[j]就表示的是用到2^i时凑成j的方案数。
            }
        }
        printf("%d\n", dp[n]);

    }
}

然后又看了另一种方法。
首先i是奇数时,dp[i] = dp[i - 1],当时我就在想,这样对不对,会不会有一种情况有1个1,然后再加上1个变成2的,后来发现不可能,因为加上1变成2就一定成偶数了。
i是偶数时,dp[i] = dp[i - 1] + dp[i / 2]
dp[i - 1]就是在奇数的基础上加上1,然后现在dp[i]所有的等式上都是有1的了,少了没有1的,没有1的就是dp[i / 2] 把dp[i / 2]的每一项乘以2就是dp[i]的没有1的方案。

#include 
#include 
#include 
using namespace std;

const int mod = 1e9;
const int maxn = 1e6 + 100;
int data[maxn];

int main()
{
    int n;
    scanf("%d", &n);
    data[0] = 1;
    data[1] = 1;
    for(int i = 2; i <= n; i++)
    {
         if(i & 1) data[i] = data[i - 1];
         else {
            data[i] = data[i - 1] + data[i / 2];
         }
         data[i] %= mod;
    }
    printf("%d\n", data[n]);
}

然后做完这个题目,又想起了之前队长说的那道题。给n个数,选<=m个,去凑sum,问有多少种方案。
dp[j][k] j代表用几个,k代表凑几,又是一个完全背包的变形。

#include 
#include 
#include 
using namespace std;

const int mod = 1e9;
const int maxn = 1e3 + 100;
int data[maxn], dp[maxn][maxn];

int main()
{
    int n, m, sum;
    scanf("%d %d %d", &n, &m, &sum);
    for(int i = 0; i < n; i++)
        scanf("%d", &data[i]);

    dp[0][0] = 1;
    for(int i = 0; i < n; i++) {
        for(int j = 1; j <= m; j++) {
            for(int k = data[i]; k <= sum; k++) {
                dp[j][k] = dp[j - 1][k - data[i]] + dp[j][k];
            }
        }
    }

    int ans = 0;
    for(int i = 1; i <= m; i++)
    {
        ans += dp[i][sum];
    }

    printf("%d\n", ans);
}

这个代码只是我们想出来的,没有真正A过题。

你可能感兴趣的:(简单dp,背包)