zoukankan      html  css  js  c++  java
  • 针对于取数字型的01背包与完全背包的一点想法


    首先,我们可以先清楚
    这类题目给出的是一个数能否有若干个数构成
    存在可以重复取,或者不可以重复取两种情况
    类似如下这样的题

    1.给定N个正整数A1,A2,…,AN,从中选出若干个数,使它们的和为M,求有多少种选择方案。
    
    2.给定一个自然数N,要求把N拆分成若干个正整数相加的形式,参与加法运算的数可以重复。
    
    求拆分的方案数 mod 2147483648的结果。
    

    首先我们可以先确定DP[i]的状态都是固定的,都是为在数值为i的情况下,能取的情况有多少种
    容易得知dp[0] = 1 作为初态
    那么易得dp[i] += dp[i - arr[x]]
    那么01背包的取法是从大到小取,即第二层循环是for(int i = m; i >= arr[j]; i --)
    这样的话 会保证每个值只取一次
    完全背包是从小到大取,即第二层循环是for(int i = arr[j]; i <= m; i ++)
    这样的话 可以多取

    还有一个关于dp状态二维的转移能否互相调换

    是不可以互相调换的,因为调换后会存在重复方案的转移,比如1 2 2 跟 2 2 1
    是一样的,但是调换for的顺序后,会导致状态的重叠
    

    为什么说dp从大到小不会重复取呢?

    因为大的先转移,避免了小的已经转移过了,然后再来转移大的,所以不会出现一个值重复取的情况
    
    如果是小的先转移,在转移大的,会存在重复取的情况的转移
    
    所以说,从大到小是01背包,从小到大是完全背包
    

    附上01背包取数字的代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int n, m;
    const int MAXN = 105;
    LL dp[MAXN * 100];
    LL arr[MAXN];
    int main(){
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i ++){
            scanf("%lld", &arr[i]);
        }
        sort(arr, arr + n);
        dp[0] = 1;
        for(int i = 0; i < n; i ++){
            for(int j = m; j >= arr[i]; j --){
                dp[j] += dp[j - arr[i]];
            }
        }
        printf("%lld
    ", dp[m]);
        return 0;
    }
    
    

    附上完全背包:

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    const int MAXN = 4005;
    typedef long long LL;
    const LL mod = 2147483648;
    LL dp[MAXN];
    int main(){
        ios::sync_with_stdio(false);
        cin >> n;
        dp[0] = 1;
        for(int i = 1; i <= n; i ++){
            for(int j = i; j <= n; j ++){
                dp[j] = (dp[j] + dp[j - i]) % mod;
            }
        }
        printf("%lld
    ", dp[n] - 1);
        return 0;
    }
    
    
  • 相关阅读:
    mongodb的sql日志
    mysql – 在WHERE子句中使用substr的SELECT语句
    MySQL视图
    Linux简单查找log
    转 信号量与PV操作
    二进制小数及 IEEE 浮点表示
    转 :原码,反码,补码
    转:C# Delegate委托 1
    C#中Invoke的用法2
    C#中Invoke的用法1
  • 原文地址:https://www.cnblogs.com/qq136155330/p/10947282.html
Copyright © 2011-2022 走看看