zoukankan      html  css  js  c++  java
  • 动态规划(三)——如何巧妙解决“双十一”购物时的凑单问题?

    1 题目描述

      淘宝的“双十一”购物节有各种促销活动,比如“满 200 元减 50 元”。假设你女朋友的购物车中有 n 个(n>100)想买的商品,她希望从里面选几个,在凑够满减条件的前提下,让选出来的商品价格总和最大程度地接近满减条件(200 元),这样就可以极大限度地“薅羊毛”。作为程序员的你,能不能编个代码来帮她搞定呢?

    2 输入

      第一行是物品的个数n(1≤n≤100000),满减大小w(1≤w≤1000000);

      第二行是n个物品的价值。

    3 输出

      输出最小值

    4 样例输入

    6 200
    34, 23, 81, 74, 57, 65
    

    5 样例输出

    203
    

    6 求解思路

      实际上,它跟第一个例子中讲的 0-1 背包问题很像,只不过是把“重量”换成了“价格”而已。购物车中有 n 个商品。我们针对每个商品都决策是否购买。每次决策之后,对应不同的状态集合。我们还是用一个二维数组 states(n)(x),来记录每次决策之后所有可达的状态。

      不过,这里的 x 值是多少呢?0-1 背包问题中,我们找的是小于等于 w 的最大值,x 就是背包的最大承载重量 w+1。对于这个问题来说,我们要找的是大于等于 200(满减条件)的值中最小的,所以就不能设置为 200 加 1 了。就这个实际的问题而言,如果要购买的物品的总价格超过 200 太多,比如 1000,那这个羊毛“薅”得就没有太大意义了。所以,我们可以限定 x 值为 1001。

      同样的,这个题目也可以使用回溯法与动态规划两种方法解决。

      这里特别强调一下当使用一个数组时,即代码中的第 53 行,j 需要从大到小来处理。如果我们按照 j 从小到大处理的话,会出现 for 循环重复计算的问题,并且还会导致计算出错。
      如果从小到大处理: stat[j + weight[i]] 的赋值为 ture,那么当 j++ 遍历到 j + weight[i] 这个值。就为 ture ,重复计算了。从大到小处理,较大的 stat[j + weight[i]] 的值,影响不到 j-- 后面的。

    7 动态规划C++版本代码如下

    #include <iostream>
    #include <math.h>
    #include <string.h>
    using namespace std;
    
    #define MAXNUM 100010
    #define DRIFT 1001
    
    // items商品价格,n商品个数, w表示满减条件,比如200
    int girlLove(int items[], int n, int w) {
        bool states[n][w + 10];
        memset(states, false, sizeof(states));
        // 第一行的数据要特殊处理
        states[0][0] = true;
        if (items[0] <= w + 10) {
            states[0][items[0]] = true;
        }
        for (int i = 1; i < n; ++i) { // 动态规划
            // 不购买第i个商品
            for (int j = 0; j <= w + 10; ++j)
                if (states[i-1][j])
                    states[i][j] = states[i-1][j];
            for (int j = 0; j <= w + 10-items[i]; ++j)
                //购买第i个商品
                if (states[i-1][j]){
                    //cout<<j+items[i]<<endl;
                    states[i][j+items[i]] = true;
                }
        }
        for(int i = 0; i <= w; i++)
            cout<<states[n - 1][i]<<" ";
        cout<<endl;
        int j;
        for (j = w; j < w + 10; ++j) {
            // 输出结果大于等于w的最小值
            if (states[n-1][j] == true)
                return j;
        }
        // 没有可行解
        if (j == w + 10 +1)
            return -1;
    }
    
    int girlLovePlus(int items[], int n, int w) {
        bool states[w + 10];
        memset(states, false, sizeof(states));
        // 第一行的数据要特殊处理
        states[0] = true;
        if (items[0] <= 3 * w)
            states[items[0]] = true;
    
        for (int i = 1; i < n; ++i) {
            for(int j = w + 10 - items[i]; j >= 0; j--)
                if(states[j])
                    states[j + items[i]] = true;
        }
        for(int i = 0; i <= w; i++)
            cout<<states[i]<<" ";
        cout<<endl;
        int j;
        for (j = w; j < w + 10; ++j) {
            // 输出结果大于等于w的最小值
            if (states[j] == true)
                return j;
        }
        // 没有可行解
        if (j == w + 10 + 1)
            return -1;
    }
    
    int main()
    {
        int value[6] = {34, 23, 81, 74, 57, 65};
        cout<<girlLove(value, 6, 200);
        cout<<endl;
        cout<<girlLovePlus(value, 6, 200);
        return 0;
    }
    
  • 相关阅读:
    IOS苹果应用IPA一键签名工具(苹果重签名,企业签名,Windows平台,时间控制)
    BZ全景编辑器
    HTML/网站一键打包APK工具(html网页打包安卓APP应用)
    HTML网页/KRPano项目一键打包EXE工具(HTML网页打包成单个windows可执行文件exe)
    KRPano资源分析工具使用说明(KRPano XML/JS解密 切片图批量下载 球面图还原 加密混淆JS还原美化)
    IOS苹果应用IPA重签名软件手机版(苹果重签名,企业签名,安卓苹果平台,时间控制)
    使用HTML一键打包IPA工具打包KRPANO全景项目
    使用HTML一键打包APK工具打包KRPANO全景项目
    使用HTML一键打包EXE工具打包KRPANO全景项目
    从现实产品生产理解创建型设计模式
  • 原文地址:https://www.cnblogs.com/flyingrun/p/13505584.html
Copyright © 2011-2022 走看看