zoukankan      html  css  js  c++  java
  • poj3624 Charm Bracelet

    http://poj.org/problem?id=3624

    题目大意:贝茜去了商场的珠宝店,发现了一个迷人的手镯。当然,她想装最好的魅力(N(1≤N≤3402)可用的魅力)。每个魅力提供的列表中都有一个重量Wi(1≤Wi≤400),一个“愿望”因素Di(1≤Di≤100),最多可以使用一次。贝茜只能支持一个重量不超过M的魅力手镯。

    *第1行:两个空格分隔的整数:N和M。

    *第2 …N+1行:第i+1行描述了具有两个空间分离整数的魅力i: Wi和Di。考虑到重量限制作为一种约束,并列举了它们的重量和可取性的魅力,推断出魅力最大可能的取值。

     

    也就是说,这个问题是01背包问题,设x[ i ]为1表示第i个珠宝放入手链,为0则不放入,那么原问题就变成了求 约束条件是 , 我们可以采用动态规划,回溯法,分支限界法等来解决该问题。这里采用动态规划求解。

     

    算法思想:动态规划

    a) 把背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选),Di表示第 i 个物品的价值,Wi表示第 i 个物品的体积(重量);

    b) 建立模型,即求max(D1X1+D2X2+…+DnXn);

    c) 约束条件,W1X1+W2X2+…+WnXn<=M;

    d) 定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值;

    e) 最优性原理是动态规划的基础,最优性原理是指“多阶段决策过程的最优决策序列具有这样的性质:不论初始状态和初始决策如何,对于前面决策所造成的某一状态而言,其后各阶段的决策序列必须构成最优策略”。判断该问题是否满足最优性原理,采用反证法证明:

    假设(X1,X2,…,Xn)是01背包问题的最优解,则有(X2,X3,…,Xn)是其子问题的最优解,

    假设(Y2,Y3,…,Yn)是上述问题的子问题最优解,则理应有(D2Y2+D3Y3+…+DnYn)+D1X1 > (D2X2+D3X3+…+DnXn)+D1X1;

    而(D2X2+D3X3+…+DnXn)+D1X1=(D1X1+D2X2+…+DnXn),则有(D2Y2+D3Y3+…+DnYn)+D1X1 > (D1X1+D2X2+…+DnXn);

    该式子说明(X1,Y2,Y3,…,Yn)才是该01背包问题的最优解,这与最开始的假设(X1,X2,…,Xn)是01背包问题的最优解相矛盾,故01背包问题满足最优性原理;

    f) 寻找递推关系式,面对当前商品有两种可能性:

    第一,背包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);

    第二,还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{ V(i-1,j),V(i-1,j-W(i))+D(i) }

    其中V(i-1,j)表示不装,V(i-1,j-W(i))+D(i) 表示装了第i个商品,背包容量减少W(i)但价值增加了v(i);

    由此可以得出递推关系式:

    1) j<W(i)      V(i,j)=V(i-1,j)

    2) j>=W(i)     V(i,j)=max V(i-1,j)V(i-1,j-W(i))+D(i)

    到此便能解决,但是你会发现,这样提交空间会溢出,不满足,所以我们要对其进行空间优化。

    g) 空间优化,每一次V(i)(j)改变的值只与V(i-1)(x) {x:1...j}有关,V(i-1)(x)是前一次i循环保存下来的值;

    因此,可以将V缩减成一维数组,从而达到优化空间的目的,状态转移方程转换为 result(j)= max{result(j), result(j-W(i))+D(i)}

    并且,状态转移方程,每一次推导V(i)(j)是通过V(i-1)(j-w(i))来推导的,所以一维数组中j的扫描顺序应该从大到小(M到0),否者前一次循环保存下来的值将会被修改,从而造成错误。

    h) 然而不足的是,虽然优化了动态规划的空间,但是该方法不能找到最优解的解组成,因为动态规划寻找解组成一定得在确定了最优解的前提下再往回找解的构成,而优化后的动态规划只用了一维数组,之前的数据已经被覆盖掉,所以没办法寻找,所以两种方法各有其优点。但是这样提交可以通过。

     1 #include <iostream>
     2 using namespace std;
     3 #define MAXN 3403
     4 #define MAXM 12881
     5 int w[MAXN];
     6 int d[MAXN];
     7 int result[MAXM];
     8 int main()
     9 {
    10     int N;
    11     int M;
    12     cin >> N >> M;
    13 
    14     for (int i = 1; i <= N; i++)
    15     {
    16         cin >> w[i] >> d[i];
    17     }
    18     for (int tempN = 1; tempN <= N; ++tempN) //对第tempN个物品
    19     {
    20         for (int tempM = M; tempM >= w[tempN]; tempM--)//背包容量从大到小
    21         {
    22             if (result[tempM] <= result[tempM - w[tempN]] + d[tempN])//比较装与不装的价值
    23             {
    24                 result[tempM] = result[tempM - w[tempN]] + d[tempN]; //二维变一维
    25             }
    26         }
    27     }
    28     cout << result[M] << endl;
    29 
    30     return 0;
    31 }
    作  者: Angel_Q 出  处:http://www.cnblogs.com/DA799422035/ 关于作者:如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。 声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
  • 相关阅读:
    怎么对Navicat for Oracle 调试
    老版本的java代码与新代码如何找出差异
    Oracle 外部表是做什么用的
    如何在Navicat 中编辑和记录
    如何使用文件对比工具文件夹比较会话菜单
    哪些工具可以用来进行Bug管理
    5类开发者须知的工具
    怎么找出代码之间的差异
    Beyond Compare不仅可以修改网页代码
    文件对比工具有哪些用途
  • 原文地址:https://www.cnblogs.com/DA799422035/p/8994899.html
Copyright © 2011-2022 走看看