• 动态规划:完全背包与完全背包计数


    有N种物品和一个容量为V的背包,每种物品的数量无限,第i种物品的重量为c[i],价值为w[i],将若干件物品装入背包,求背包所放物品的最大价值

    这时每种物品都有取0件,取1件,取2件等若干种情况

    采用朴素的实现方式是类比01背包的状态转移方程,我们给出这样的形式,我们令f[i][v]表示前i件物品恰放入一个容量为v的背包时的最大价值

    f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}

    与01背包的转移方程相比,这里仅仅是多了一个常数k,表示0,1,2,3件的各种情况

    但是这时的时间复杂度是要超过O(V*N)的

    我们给出其优化形式,类比01背包的滚动数组的实现思路,滚动数组是倒着滚的,这里正着滚就可以在拥有自己物品的状态上加以继承达到放多件的目的

    f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

    将其用滚动数组实现就变成了

     f[v]=max{f[v],f[v-c[i]]+w[i]}

    这就是解决完全背包问题的最佳状态转移方程

    我们给出其实现

     1 #include<algorithm>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=2005;
     6 const int maxv=50005;
     7 int N,V;
     8 int v[maxn],w[maxn];
     9 int ans=0;
    10 int f[maxv];
    11 int T;
    12 int main()
    13 {
    14     scanf("%d",&T);
    15     while(T--)
    16     {
    17         scanf("%d%d",&N,&V);
    18         for(int i=1;i<=N;i++)
    19         {
    20             scanf("%d%d",&v[i],&w[i]);
    21         }
    22         memset(f,128,sizeof(f));
    23         f[0]=0;
    24         for(int i=1;i<=N;i++)
    25         for(int j=v[i];j<=V;j++)
    26         {
    27             f[j]=max(f[j],f[j-v[i]]+w[i]);
    28         }
    29         if(f[V]<=0)
    30             printf("NO
    ");
    31         else
    32             printf("%d
    ",f[V]);
    33     }
    34     return 0;
    35 }
    36  

    在这里考虑一个细节,那就是满不满包,如果满包,要记得将所有f数组元素设置为负无穷,然后f[0]=0就好了

    然后我们考虑其变式形式,来源是货币系统这道题目

    题意是这样的,给定了几种货币的面值,然后问你用这几种货币来凑一个钱数,有多少种拼凑方法

    因为我们要求的是方案数,这里每一种物品的质量和价值就不那么显然了

    我们用f[i]表示面值为i时的方案数,给出转移方程

    f[0]=1
    f[j]+=f[j-v[i]]

    接下来给出完整的实现:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm> 
     4 using namespace std;
     5 const int maxn=30,maxv=10005;
     6 int N,V;
     7 int v[maxn];
     8 long long ans=0;
     9 long long f[maxv];
    10 void dp()
    11 {
    12     f[0]=1;
    13     for(int i=1;i<=N;i++)
    14     for(int j=v[i];j<=V;j++)
    15      f[j]+=f[j-v[i]];
    16     ans=f[V];
    17 }
    18 int main()
    19 {
    20     cin>>N>>V;
    21     for(int i=1;i<=N;i++)
    22         cin>>v[i];
    23     dp();
    24     cout<<ans<<endl;
    25     return 0;
    26 }
  • 相关阅读:
    关于使用AWS的centos
    MySQL高可用配置(主从复制)
    tomcat+apache+jk
    Zabbix-1.8.14 安装
    centos6.5下,使用虚拟ftp用户
    java小数位-DecimalFormat(转)
    java collection 类图
    log4j详解(转)
    java强软弱虚引用详解(转载)
    Java深入理解文章(转载)
  • 原文地址:https://www.cnblogs.com/aininot260/p/9308601.html
Copyright © 2020-2023  润新知