题解 | #牛妹的春游#

牛妹的春游

http://www.nowcoder.com/practice/b27955f3fb6d42d9b18f83ae065cbe55

牛妹的春游

描述
给出两个正整数x,y,另给出若干个数对,请挑选若干数对使得挑出的数对的和不小于x,的和不小于y,计算挑出数对的的和的最小值

注:
每个数对只能挑选一次,x和y均小于2000

方法一

思路分析

本题可以抽象为动态规划中的经典问题--背包问题,设置x,y分别表示需要物品A的数量,物品B的数量,而两个物品是捆绑销售的,数对分别表示物品A的数量、物品B的数量表示购买个物品A以及个物品B情况下的钱数。要使得购买的物品A的数量不小于x,购买物品B的数量不小于y,所需要的钱最少。由于存在两种物品,按照0-1背包的思想,需要设置三维数组,与0-1背包问题不同的是本题并没有设置最大的容量,而是需要的容量,因此对于转移方程如果容量减到负数了,就从0转移,这样即使拿了更大的容量也不会数组越界,转移也是正确的。转移方程如下:


  • 上式k表示第k个捆绑物品,表示对于物品A容量减到负数了,就从0转移,即使拿了更大的容量也不会数组越界,转移也是正确的;
  • 同样的表示对于物品B容量减到负数了,就从0转移,即使拿了更大的容量也不会数组越界,转移也是正确的;

核心代码

class Solution {
public:
    /**
     * 
     * @param breadNum int整型 
     * @param beverageNum int整型 
     * @param packageSum int整型vector<vector<>> 每个一维数组中有三个数,依次表示这个包装里面的面包数量、饮料数量、花费
     * @return int整型
     */
    int minCost(int breadNum, int beverageNum, vector<vector<int> >& packageSum) {
        // write code here
        int n=packageSum.size();
        vector< vector < vector<int> > > dp(n+1,vector< vector<int> >(breadNum+1,vector<int>(beverageNum+1,2e9 + 7)));
        dp[0][0][0]=0;//初始化取第0个包装,0个A,0个B的最小花费为0
        for(int k=1;k<=n;k++)
        {
            int x=packageSum[k-1][0];
            int y=packageSum[k-1][1];
            int z=packageSum[k-1][2];
            for(int i=0;i<=breadNum;i++)
            {
                
                for(int j=0;j<=beverageNum;j++)
                {
                      dp[k][i][j] = min(dp[k-1][i][j], dp[k-1][max(i-x,0)][max(j-y,0)]+z);
                      //表示可选物品为1-k,物品A容量为i,物品B容量为j的最优值(钱最少)
                }
                  
            }
        }
        return dp[n][breadNum][beverageNum];
    }
};
复杂度分析
  • 时间复杂度:存在三层循环,总的时间复杂度为$O(n*breadNum*beverageNum)$,其中$n$表示所给的数对的个数
  • 空间复杂度:需要借助于一个二维数组存储最小费用,需要额外的空间为$O(n*breadNum*beverageNum)$

方法二

思路分析

    针对第一种方法,可以利用滚动数组的思想,减小数组的维数,从而降低空间复杂度,转移方程如下:

  • 上式k表示第k个捆绑物品,表示对于物品A容量减到负数了,就从0转移,即使拿了更大的容量也不会数组越界,转移也是正确的;
  • 同样的表示对于物品B容量减到负数了,就从0转移,即使拿了更大的容量也不会数组越界,转移也是正确的;

核心代码

class Solution {
public:
    /**
     * 
     * @param breadNum int整型 
     * @param beverageNum int整型 
     * @param packageSum int整型vector<vector<>> 每个一维数组中有三个数,依次表示这个包装里面的面包数量、饮料数量、花费
     * @return int整型
     */
    int minCost(int breadNum, int beverageNum, vector<vector<int> >& packageSum) {
        // write code here
        vector<vector<int>> dp(breadNum+1,vector<int>(beverageNum+1,2e9 + 7));//定义二维数组dp[i][j]表示i个A,j个B的最小花费
        dp[0][0]=0;//初始化0个A,0个B的最小花费为0
        int n=packageSum.size();
        for(int k=0;k<n;k++)
        {
            int x=packageSum[k][0];
            int y=packageSum[k][1];
            int z=packageSum[k][2];
            for(int i=breadNum;i>=0;i--)
            {
                for(int j=beverageNum;j>=0;j--)
                    dp[i][j] = min(dp[i][j], dp[max(i-x,0)][max(j-y,0)]+z);
                //当前捆绑套餐内A或者B大于需要的数量,那么当前剩余需求为0
            }
        }
        return dp[breadNum][beverageNum];
    }
};
复杂度分析
  • 时间复杂度:存在三层循环,总的时间复杂度为$O(n*breadNum*beverageNum)$,其中$n$表示所给的数对的个数
  • 空间复杂度:需要借助于一个二维数组存储最小费用,需要额外的空间为$O(breadNum*beverageNum)$

全部评论

相关推荐

最喜欢秋天的火龙果很...:第一份工作一定要往大的去,工资低点没事。后面换工作会更好找,即使你去小公司,你也不可能不会换工作的。所以找大的去
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 长得好看会提高面试通过率吗? #
3209次浏览 43人参与
# HR最不可信的一句话是__ #
1021次浏览 32人参与
# MiniMax求职进展汇总 #
24901次浏览 321人参与
# 春招至今,你的战绩如何? #
14766次浏览 137人参与
# AI面会问哪些问题? #
893次浏览 22人参与
# 你的实习产出是真实的还是包装的? #
2722次浏览 52人参与
# 米连集团26产品管培生项目 #
7079次浏览 224人参与
# 沪漂/北漂你觉得哪个更苦? #
1235次浏览 38人参与
# 你做过最难的笔试是哪家公司 #
1131次浏览 20人参与
# AI时代,哪个岗位还有“活路” #
2684次浏览 49人参与
# XX请雇我工作 #
51147次浏览 171人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7966次浏览 43人参与
# 简历第一个项目做什么 #
32073次浏览 357人参与
# 简历中的项目经历要怎么写? #
310908次浏览 4257人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152832次浏览 889人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187556次浏览 1123人参与
# AI时代,哪些岗位最容易被淘汰 #
64539次浏览 864人参与
# 如果重来一次你还会读研吗 #
229974次浏览 2011人参与
# 投格力的你,拿到offer了吗? #
178254次浏览 891人参与
# 你怎么看待AI面试 #
180654次浏览 1296人参与
# 正在春招的你,也参与了去年秋招吗? #
364172次浏览 2641人参与
# 腾讯音乐求职进展汇总 #
160822次浏览 1114人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务