leetcode638及STL中inner_product

遇到No.638题,总结一下看到的discuss中用的比较好的两点

题目描述:

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: 14 Explanation: 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 0B In 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: 11 Explanation: 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.

总结一下呢也就是说当前给出目标needs数组,有单独的售价price和打包优惠的组合special,但是有一个前提,最终买到的各种条目的数量必须和needs中一样。

思路:

那么毫无疑问,打包一定比单独购买便宜,那么肯定是想办法在special中进行DFS尽量多的购买,但因为题目限制,所以一旦超数是不行的,不够的只能单独买来凑齐。

那么先看一下在discuss中的一个答案,将DFS进行简化了:

class Solution {
public:
    int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
        int res=inner_product(price.begin(),price.end(),needs.begin(),0); //直接内积,
        for(auto offer:special){
            vector<int> v=can(needs,offer);
            if(v.empty())
                continue; //此时说明返回的是个空集,也就表示当前的special是无法满足的,直接下一个进行判断
            res=min(res,offer.back()+shoppingOffers(price,special,v)); //当前所需为减去使用过的special后的v
        }
        return res;
    }
private:
    vector<int> can(vector<int>& needs,vector<int>& offer){
        vector<int> v(needs.size(),0);
        for(int i=0;i<needs.size();++i){
            if(offer[i]>needs[i])
                return vector<int>{};
            else
                v[i]=needs[i]-offer[i];
        }
        return v;
    }
};

来分析一下巧妙的地方吧。

首先第一个,STL中内积的使用。因为如果我们单独购买,那么肯定是遍历数组对应项相乘,但此时直接一个inner_product妥了

inner_product的使用:分三种来考虑

假设:

int init = 100;
int series1[] = {10,20,30};
int series2[] = {1,2,3};

  •  
    inner_product(vec1.begin(),vec1.end(),vec2.begin(),init)

    此时也就是在init的基础上进行累加,内积的范围是什么呢?[vec1.begin(),vec1.end()),注意,这里一个是左闭区间右开区间。之后从vec2的begin()位置,我们使用匹配长度的项与vec1中对应相乘。此时输出240

  • inner_product(vec1.begin(),vec1.end(),vec2.begin(),init,minus<int>(),divides<int>());

    此时,求内积以及初始值和第一种是一样的,那么后两项呢?第三项minus表示负号为是负,第四项表示对应项相除,之后根据符号位是负进行累加,也就是本来240-(10/2)-(20/2)-(30/3),此时输出70

  • int myproduct (int x, int y) {return x+y;}
    inner_product(vec1.begin(),vec1.end(),vec2.begin(),init,minus<int>(),myproduct);

        此时,自己定义第四项操作,同样的,此时输出为34

那么再说程序中第二点巧妙的地方,我们知道,DFS到无法使用special之后,剩余不足的需要用单个补充,那么如何操作能使程序较为简单呢?

在开头的时候我们直接计算了inner_product,此时也就是所需单个购买的值,那么我们就可以考虑记录每使用一次special后仍然需要的每一项个数(也就是修正needs数组),将cost进行累加,那么res每一次只要取Min值即可。

res=min(res,offer.back()+shoppingOffers(price,special,v));

参考博客:

https://blog.csdn.net/zhangyulin54321/article/details/7870656

https://blog.csdn.net/Wang_1997/article/details/65723134

猜你喜欢

转载自blog.csdn.net/qq_26896213/article/details/83823920