638. Shopping Offers 深度优先遍历、递归、存储技术(基于递归的动态规划)

来源:互联网 发布:淘宝判定为广告的评价 编辑:程序博客网 时间:2024/05/28 22:07

In LeetCode Store, there are some kinds of items to sell. Each item has a price.

However, there are some special offers, and a special offer consists of one or more different kinds of items with a sale price.

You are given the each item's price, a set of special offers, and the number we need to buy for each item. The job is to output the lowest price you have to pay for exactly certain items as given, where you could make optimal use of the special offers.

Each special offer is represented in the form of an array, the last number represents the price you need to pay for this special offer, other numbers represents how many specific items you could get if you buy this offer.

You could use any of special offers as many times as you want.

Example 1:

Input: [2,5], [[3,0,5],[1,2,10]], [3,2]Output: 14Explanation: There are two kinds of items, A and B. Their prices are $2 and $5 respectively. In special offer 1, you can pay $5 for 3A and 0BIn special offer 2, you can pay $10 for 1A and 2B. You need to buy 3A and 2B, so you may pay $10 for 1A and 2B (special offer #2), and $4 for 2A.

Example 2:

Input: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]Output: 11Explanation: The price of A is $2, and $3 for B, $4 for C. You may pay $4 for 1A and 1B, and $9 for 2A ,2B and 1C. You need to buy 1A ,2B and 1C, so you may pay $4 for 1A and 1B (special offer #1), and $3 for 1B, $4 for 1C. You cannot add more items, though only $9 for 2A ,2B and 1C.

Note:

  1. There are at most 6 kinds of items, 100 special offers.
  2. For each item, you need to buy at most 6 of them.
  3. You are not allowed to buy more items than you want, even if that would lower the overall price.
题目描述:
给定一组商品的价格和针对这些商品的打折组合,购物者要买指定数量的不同商品,求所需花费的最少的钱?
注意题目的要求,不能买的比所需商品多,即便可能花更少的钱。比如第二个例子所示
思路1:使用递归
这种思路就是依次尝试所有可能的折扣,每尝试一次,更新一下needs,调用下一层递归,在继续尝试所有可能的折扣方案。当然,这些折扣方案是和不采用折扣方案相比的。
代码如下:
class Solution {public:    int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {        return shopping(price,special,needs);    }    //下面是递归函数    int shopping(vector<int>& price, vector<vector<int>>& special, vector<int>& needs){        //首先求出不大折扣所需的钱是多少        int res=0;        for(int i=0;i<price.size();i++)        {            res+=price[i]*needs[i];        }        //下面的循环,每次选择一个折扣方案,看看是否可行(可行指的是采用折扣方案不会买到多余的商品)        //如果可行,就将减掉折扣之后的needs传入到下一个递归中去        for(auto s:special)        {            //针对每一种折扣方案,都首先复制一份购物单列表,因为这是一种尝试            vector<int> clone(needs);            int j=0;            for(;j<clone.size();j++)            {                clone[j]=clone[j]-s[j];                if(clone[j]<0)//如果这种折扣方案的某个商品数量大于当前这种商品的需求量,这种折扣方案是不可行的                    break;                            }            if(j==clone.size())                res=min(res,s[j]+shopping(price,special,clone));        }        return res;    }};
思路2:
递归改进版本。考虑通过存储技术消除重复的递归。
思路1中,首先选择第一种折扣方案,第二层递归选择第二种折扣方案的话,那首先第一层选择第二种折扣方案,第二层递归也可以选择第一种折扣方案。
考虑记录这种重复的过程,因为每层递归都是求得当前情况下的最少花费。因此记录当前的needs和花费。比如上述情况,先选择第一种折扣方案再选择第二种折扣方案和反过来选择得到的needs及花费是一样的。如果第一种选择已经求到了,第二种选择直接返回结果即可。
由于needs和花费是不同的类型。最好的方式是使用map关联容器。
代码如下:
class Solution {public:    int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {        map<vector<int>,int> p;        return shopping(price,special,needs,p);    }    //下面是递归函数    int shopping(vector<int>& price, vector<vector<int>>& special, vector<int>& needs,map<vector<int>,int>& p){        //首先求出不大折扣所需的钱是多少        if(p.find(needs)!=p.end())//如果当前的needs最小花费已经球出来了,直接返回            return p[needs];        int res=0;        for(int i=0;i<price.size();i++)        {            res+=price[i]*needs[i];        }        //下面的循环,每次选择一个折扣方案,看看是否可行(可行指的是采用折扣方案不会买到多余的商品)        //如果可行,就将减掉折扣之后的needs传入到下一个递归中去        for(auto s:special)        {            //针对每一种折扣方案,都首先复制一份购物单列表,因为这是一种尝试            vector<int> clone(needs);            int j=0;            for(;j<clone.size();j++)            {                clone[j]=clone[j]-s[j];                if(clone[j]<0)//如果这种折扣方案的某个商品数量大于当前这种商品的需求量,这种折扣方案是不可行的                    break;                            }            if(j==clone.size())                res=min(res,s[j]+shopping(price,special,clone,p));        }        p[needs]=res;//记录当前needs的最小花费        return res;    }};





阅读全文
0 0