zoukankan      html  css  js  c++  java
  • 高深的dp POJ 2229Sumsets

        对于这个问题, 我们显然可以看出来, 当他是奇数的时候, 直接等于他的前一个偶数  

        dp [ i ] = dp [ i - 1] ;

        那么问题, 当它是偶数的时候, 我们应该怎么进行 dp 记忆化搜索并且递归?  

      不知你是否记得化分数问题, 不记得话,请看dp初级内容, 就在DP 内容

      我们这里也是同样采取分成组内部有 1, 和分成组的内部没有 1

        当有一的时候, 那么就和上面的奇数一样, 具体说一下为什么, 以为它是偶数,一旦他有一, 那么至少为 2 个, 我们把这两个 1 进行合并, 然后看成  i - 1 中剩下的 一个 1 ,完成了递归

        当没有一的时候, 我们可以直接 除以二进行处理, 以为最小化单元就可以看做之前的最小化单元 1 , 

      所以说  dp [ i ]  =  dp [ i - 1] + dp [ i / 2 ] ; 

      

        下面是代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cctype>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <queue>
    #include <list>
    #include <map>
    #include <stack>
    #include <set>
    using namespace std;
    const int MAX_N = 1000010;
    const int MOD = 1000000000;
    int dp[MAX_N];
    // TM 递归会栈溢出, 这也太狗了吧!!
    int rec(int n){
        if(dp[n] != -1) return dp[n];
        else{
            if(n & 1)   //奇数
                dp[n] = rec(n - 1);
            else{
                dp[n] = (rec(n - 1) + rec(n >> 1)) % MOD;
            }
        }
        return dp[n];
    }
    
    int main()
    {
        int n;
        memset(dp, 0, sizeof(dp)); dp[1] = 1; dp[2] = dp[3] = 2;
        cin>>n;
        for(int i = 4; i <= n; i++){
            dp[i] = dp[i - 1];
            if(!(i & 1)){
                dp[i] += dp[i>>1];
            }
            dp[i] %= MOD;
        }
        printf("%d
    ", dp[n]);
        return 0;
    }

    除了这一种写法还会有另外一种的写法:

    这个方法类似于背包

    然后就是原来的基础上进行加上了新的  2  的倍数!

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int mod = 1e9;
    const int maxn = 1000005;
    
    int main(){
        int c[22] = {1};
        long long int dp[maxn] = {0};
        for(int i = 1; i < 22; i++)
            c[i] = c[i-1] * 2;
        dp[0] = 1; 
        int n;
        cin >> n;
        for(int i = 0; i < 22; i++){
            for(int j = c[i];j < n+1; j++){
                //当他循环的时候, 相当于 在最大 为 c[i] 因子的限制条件下, 他的种类数目 
                dp[j] = dp[j] + dp[j-c[i]];
                // 这个递归关系是相当于有了一个甚至多个 c[i] 的时候, 进行递归, 然后加上之前没有的 
                if(dp[j] > mod) dp[j] = dp[j] % mod;
            }
        }
        printf("%lld
    ", dp[n]);
        return 0;
    }

    但是图片中有点小错误, 不知道你发现了没有, 应该是: dp [ i ] [ j ]  = dp [ i - 1 ] [ j ]   + dp [ i  ] [  j - w [ i ] ]   !!!

    所以说, 上代码 :

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define Maxn 1000005
    using namespace std;
    int n;
    int w[Maxn];
    int cnt=0;
    int dp[Maxn];
    int main()
    {
        scanf("%d",&n);
        for(int i=0;(1<<i)<=n;i++)//构造所有物品
            w[cnt++]=(1<<i);
        dp[0]=1;
        for(int i=0;i<cnt;i++)
            for(int j=w[i];j<=n;j++)
                dp[j]=(dp[j]+dp[j-w[i]])%1000000000;//取余
    
        printf("%d
    ",dp[n]);
        return 0;
    }
  • 相关阅读:
    JVM Inline
    Lattice
    编译技术
    sql-server-on-linux
    concurrency 方面的books
    Linux debugger lldb
    javaperformanceoptimization
    Understanding The Linux Virtual Memory Manager
    web performance tu ning
    linux io architecture
  • 原文地址:https://www.cnblogs.com/lucky-light/p/11504786.html
Copyright © 2011-2022 走看看