题意 : 给出一个数 n ,问如果使用 2 的幂的和来组成这个数 n 有多少种不同的方案?

分析 : 

完全背包解法

将问题抽象==>有重量分别为 2^0、2^1、2^2…2^k 的物品且每种物品可无限取,问有多少种方案来填满容量为 n 的背包?

之前并不知道背包还能用来计数.......

有一道裸的背包计数问题可以作为练习 ==> HDU 1284

定义 dp[ i ][ j ] 为前 i 种物品组成总重量 j 的方案数为多少、初始化为 dp[ 0 ][ 0 ] = 1 其他为 0

则状态转移方程为  dp[ i ][ j ] += dp[ i-1 ][ j - k*w[ i ] ] ( k ≥ 0 && j ≥ k*w[i] )

最后类似于完全背包的递推方程,可化简为一维线性的递推式 dp[ j ] += dp[ j - w[ i ] ] ( j ≥ w[i] )

#include<bits/stdc++.h>
using namespace std;
;
const int mod  = 1e9;
int dp[maxn];
int main(void)
{
    int n;
    while(~scanf("%d", &n)){
        memset(dp, , sizeof(dp));
        dp[] = ;
        ; i<; i++)
            <<i); j<=n; j++){
                dp[j] += dp[j-(<<i)];
                if(dp[j] >= mod) dp[j] -= mod;
            }
        printf("%d\n", dp[n]);
    }
    ;
}

找递推规律解法

现分别来考虑 n 为奇数还有偶数的情况

① n 为奇数的时候可以发现只是在 n-1( 偶数 ) 每种方案的后面多了个 1 而已并不能多组出新的方案,所以 dp[ 奇数 ] = dp[ 奇数 -1 ]

② n 为偶数,此时可以将所有的方案数分成两类 ( 组合方案中包含 1 的 ) 与 ( 组合方案中不包含 1 的 )

首先来看组合方案中包含 1 的情况

可以将其看成在 n-1 的方案中每个方案的后面多加一个 1 来组成,此时方案数和 n-1 是一样的即 dp[ n - 1 ]

而组合方案中不包含 1 的情况

如果将小数据打表列出来会发现这种情况的方案数实际等于 n/2 的方案数,即 dp[ n/2 ]

所以最后的答案应该为 dp[ n ] = dp[ n-1 ] + dp[ n/2 ]

#include<bits/stdc++.h>
using namespace std;
;
const int mod  = 1e9;
int dp[maxn];
int main(void)
{
    int n;
    while(~scanf("%d", &n)){
        dp[] = ;
        dp[] = dp[] = ;
        dp[] = dp[] = ;
        dp[] = dp[] = ;
        ) printf("%d\n", dp[n]);
        else{
            ; i<=n; i++){
                ) dp[i] = dp[i-];
                ] + dp[i>>];
                if(dp[i] >= mod) dp[i] -= mod;
            }
            printf("%d\n", dp[n]);
        }
    }
    ;
}

现举几个例子来解释一下

dp[1] = 1

1

------------------------------------------------------------------------------------

dp[2] = 2

1+1、2

------------------------------------------------------------------------------------

dp[3] = dp[3-1] = 2

1+1+1、2+1 ( 奇数情况 == 奇数-1中所有方案数后面添 1 )

------------------------------------------------------------------------------------

dp[4] = dp[4-1] + dp[4/2] = 4

1+1+1+1、2+1+1 ( 这个就是 dp[4-1] 的情况 == 在 n-1 的所有方案数后面添 1 )

2+2、4 ( 这里的所有方案 / 2 后会发现实际就对应了 dp[2] ,所以是 dp[ 4/2 ] )

------------------------------------------------------------------------------------

dp[5] = dp[5-1] = 4

1+1+1+1+1、2+1+1+1

2+2+1、4+1

------------------------------------------------------------------------------------

dp[6] = dp[6-1] + dp[ 6/2 ] = 6

1+1+1+1+1+1、2+1+1+1+1、2+2+1+1、4+1+1 ( 此为 dp[ 6-1 ] 意义和上面所述一样 )

2+2+2、4+2 ( 方案所有数 / 2 后变成 1+1+1、2+1 和 dp[3] 是对应的! )

......

POJ 2229 sumset ( 完全背包 || 规律递推DP )的更多相关文章

  1. poj 2229 【完全背包dp】【递推dp】

    poj 2229 Sumsets Time Limit: 2000MS   Memory Limit: 200000K Total Submissions: 21281   Accepted: 828 ...

  2. ACM_递推题目系列之一涂色问题(递推dp)

    递推题目系列之一涂色问题 Time Limit: 2000/1000ms (Java/Others) Problem Description: 有排成一行的n个方格,用红(Red).粉(Pink).绿 ...

  3. 递推DP URAL 1167 Bicolored Horses

    题目传送门 题意:k个马棚,n条马,黑马1, 白马0,每个马棚unhappy指数:黑马数*白马数,问最小的unhappy值是多少分析:dp[i][j] 表示第i个马棚放j只马的最小unhappy值,状 ...

  4. 递推DP URAL 1017 Staircases

    题目传送门 /* 题意:给n块砖头,问能组成多少个楼梯,楼梯至少两层,且每层至少一块砖头,层与层之间数目不能相等! 递推DP:dp[i][j] 表示总共i块砖头,最后一列的砖头数是j块的方案数 状态转 ...

  5. 递推DP URAL 1260 Nudnik Photographer

    题目传送门 /* 递推DP: dp[i] 表示放i的方案数,最后累加前n-2的数字的方案数 */ #include <cstdio> #include <algorithm> ...

  6. 递推DP URAL 1353 Milliard Vasya's Function

    题目传送门 /* 题意:1~1e9的数字里,各个位数数字相加和为s的个数 递推DP:dp[i][j] 表示i位数字,当前数字和为j的个数 状态转移方程:dp[i][j] += dp[i-1][j-k] ...

  7. 递推DP URAL 1119 Metro

    题目传送门 /* 题意:已知起点(1,1),终点(n,m):从一个点水平或垂直走到相邻的点距离+1,还有k个抄近道的对角线+sqrt (2.0): 递推DP:仿照JayYe,处理的很巧妙,学习:) 好 ...

  8. 递推DP 赛码 1005 Game

    题目传送门 /* 递推DP:官方题解 令Fi,j代表剩下i个人时,若BrotherK的位置是1,那么位置为j的人是否可能获胜 转移的时候可以枚举当前轮指定的数是什么,那么就可以计算出当前位置j的人在剩 ...

  9. 递推DP HDOJ 5328 Problem Killer

    题目传送门 /* 递推DP: 如果a, b, c是等差数列,且b, c, d是等差数列,那么a, b, c, d是等差数列,等比数列同理 判断ai-2, ai-1, ai是否是等差(比)数列,能在O( ...

随机推荐

  1. Chapter03 第一节 简单变量

    3.1 简单变量 定义一个变量后,系统根据变量类型的不同在内存的不同区域分配一个空间,将值复制到内存中,然后用户通过变量名访问这个空间. 3.1.1 变量名 变量名的命名规则: 只能使用字母.数字.下 ...

  2. 【Linux开发】V4L2驱动框架分析学习

    Author:CJOK Contact:cjok.liao#gmail.com SinaWeibo:@廖野cjok 1.概述 Video4Linux2是Linux内核中关于视频设备的内核驱动框架,为上 ...

  3. diff patch比较文件打补丁

    比较文件将结果保存到patch文件:diff -u test1.txt test2.txt > patchfile test1.txt应用patch文件,并备份(test1.txt.orig): ...

  4. Web安全测试中常见逻辑漏洞解析(实战篇)

    Web安全测试中常见逻辑漏洞解析(实战篇) 简要: 越权漏洞是比较常见的漏洞类型,越权漏洞可以理解为,一个正常的用户A通常只能够对自己的一些信息进行增删改查,但是由于程序员的一时疏忽,对信息进行增删改 ...

  5. new 和 malloc 的区别 及使用

    Malloc: 定义上:malloc  memory allocation 动态内存分配 是c中的一个函数 使用方法: extern void *malloc(unsigned int num_byt ...

  6. P5016龙虎斗

    这道题是2018年普及组的第二题,是一个模拟题. 首先计算出双方各自的势力,然后将增援的队伍势力加上,比较此时双方势力,并且作差,最后枚举将公平兵加在哪一个兵营.看似简单的题被我20分钟就写完了,但是 ...

  7. 思维体操: HDU1049Climbing Worm

    Climbing Worm Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  8. 分布式理论: CAP、BASE (转)

    分布式系统的CAP理论是由Eric Brewer于1999年首先提出的,又被称作布鲁尔定理(Brewer's theorem),CAP是对Consistency(一致性).Availability(可 ...

  9. Python数据结构与算法?

    数据结构与算法(Python) 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是 ...

  10. Redis---键的过期时间及数据淘汰策略

    5.键的过期时间   Redis可以为每个键设置过期时间,当键过期时,会自动删除该键.   对于散列表这种容器,只能为整个键设置过期时间(整个散列表),而不能为键里面的单个元素设置过期时间. 6.数据 ...