zoukankan      html  css  js  c++  java
  • 01背包问题:Charm Bracelet (POJ 3624)(外加一个常数的优化)

    Charm Bracelet    POJ 3624

    就是一道典型的01背包问题:

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #include<string.h>
     5 using namespace std;
     6 int a[3405],b[3405];
     7 int c[12888];
     8 int main()
     9 {
    10     int n,m,i,j;
    11     while(scanf("%d%d",&n,&m)!=EOF)
    12     {
    13         for(i=1;i<=n;i++)
    14             scanf("%d%d",&a[i],&b[i]);
    15         memset(c,0,sizeof(c));
    16         for(i=1;i<=n;i++)
    17             for(j=m;j>=a[i];j--)
    18             if(c[j]<c[j-a[i]]+b[i])
    19             c[j]=c[j-a[i]]+b[i];
    20         printf("%d
    ",c[m]);
    21     }
    22     return 0;
    23 }

     还有一种方法,使用一个简单的技巧:滚动数组(DP中常用的:优化内存)

    1.4初始化的细节问题
    我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现方法是在初始化的时候有所不同。
    如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其它F[1..V]均设为−∞,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。
    如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0..V]全部设为0。
    这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
    这个小技巧完全可以推广到其它类型的背包问题,后面不再对进行状态转移之前的初始化进行讲解。(这个理解较易)
    1.5一个常数优化
    上面伪代码中的
    fori←1toN
    forv←VtoCi

    中第二重循环的下限可以改进。它可以被优化为
    fori←1toN
    forv←Vtomax(V−ΣNiWi,Ci)
    这个优化之所以成立的原因请读者自己思考。(提示:使用二维的转移方程思考较易。)

    这个较容易理解:

    那个常数优化不错,之可惜他打错了(有点怀疑)

    由于只需要最后f[v]的值,倒推前一个物品,其实只要知道f[v-w[n]]即可。以此类推,对以第j个背包,其实只需要知道到f[v-sum{w[j..n]}]即可,即代码中的

    for i=1..N
    for v=V..0

    可以改成

    for i=1..n
    bound=max{V-sum{c[i..n]},c[i]}
    for v=V..bound

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #include<string.h>
     5 using namespace std;
     6 int a[3405],b[3405];
     7 int c[12888];
     8 int sum[3405],sb;
     9 int main()
    10 {
    11     int n,m,i,j;
    12     while(scanf("%d%d",&n,&m)!=EOF)
    13     {
    14         for(i=1;i<=n;i++)
    15             scanf("%d%d",&a[i],&b[i]);
    16         sum[n]=a[n];
    17         for(i=n-1;i>=1;i--)
    18             sum[i]=a[i]+sum[i+1];
    19         memset(c,0,sizeof(c));
    20         for(i=1;i<=n;i++)
    21             for(j=m,sb=max(m-sum[i],a[i]);j>=sb;j--)
    22             if(c[j]<c[j-a[i]]+b[i])
    23             c[j]=c[j-a[i]]+b[i];
    24         printf("%d
    ",c[m]);
    25     }
    26     return 0;
    27 }
  • 相关阅读:
    7天入门JavaScript,第一天
    linux 下 启动web项目报 java.net.UnknownHostException
    HashMap 和 Hashtable
    Servlet 两种跳转方式
    SpringMVC
    把当前时间(NSDate)转为字符串
    写入数据到Plist文件中时,第一次要创建一个空的数组,否则写入文件失败
    实现多个UIView之间切换的动画效果
    missing required architecture x86_64 in file 不支持64位
    获取IOS bundle中的文件
  • 原文地址:https://www.cnblogs.com/tt123/p/3280471.html
Copyright © 2011-2022 走看看