题解 | #牛妹的春游#

牛妹的春游

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

题意:

有若干个物品,每个物品有两种费用 图片说明 和一个价值 图片说明 ,
现在给你两个数字 图片说明图片说明 ,每种物品可以选也可以不选,让你找到一种组合物品的方案,使得 图片说明 并且 图片说明图片说明 最小。

方法一(暴力DFS,不可AC)

依次递归地考虑每个物品 选/不选,最后统计符合要求的答案求最小值即可。
具体的,我们设递归函数 图片说明 表示当前考虑到第 图片说明 个物品,当前的 图片说明 总和为 图片说明 ,当前的 图片说明 总和为 图片说明 ,当前的 图片说明 总和为 图片说明 ,最后统计即可。
代码:

class Solution {
public:
    int n;//物品总数
    int x,y;
    int ans;//答案
    vector<vector<int> > datas;//物品数据
    void dfs(int i,int j,int k,int v){
        if(i>=n){
            //n个物品全部决策完毕
            if(j>=x&&k>=y)ans=min(ans,v);
            return;
        }
        dfs(i+1,j+datas[i][0],k+datas[i][1],v+datas[i][2]);//选
        dfs(i+1,j,k,v);//不选
    }
    int minCost(int breadNum, int beverageNum, vector<vector<int> >& packageSum) {
        this->n=packageSum.size();
        this->x=breadNum;
        this->y=beverageNum;
        this->ans=0x3f3f3f3f;
        this->datas=packageSum;
        dfs(0,0,0,0);//从第0个物品开始考虑
        return ans;
    }
};

时间复杂度:图片说明 ,每个物品有两种方案,总共有n个物品,故方案总数为图片说明 ,时间复杂度为图片说明
空间复杂度:图片说明 ,存储物品数据所需图片说明 级别的内存,递归的深度也为图片说明 级别,故空间复杂度为图片说明

方法二(二维费用背包,可AC)

显然这是二维费用背包问题,对于每个物品,第一维费用为 图片说明 ,第二维费用为 图片说明 ,价值为 图片说明
具体的,我们可以设 图片说明 表示前 图片说明 个物品,当前第一维 刚好花费 的费用为 图片说明 ,第二维 刚好花费 的费用为 图片说明 ,价值总和的最小值。
显然有:图片说明
由于每个 图片说明图片说明 都是正数,我们可以采用 滚动数组 的形式优化掉第一维空间,
即:图片说明
这边还有一个问题,就是我们最后所选择的费用总和可以大于当前已有的费用总和,即最后所选物品的 图片说明 总和可以大于 图片说明 ,或者所选物品的 图片说明 总和可以大于 图片说明

那么我们可以如何处理呢?
我们设当前背包的容量分别为『以前的j』,『以前的k』,另外有新的状态表示的背包容量『新的j』,『新的k』
我们以『以前的j』,『以前的k』作考量:

假如对于『以前的j』,『以前的k』,有一个物品的费用超出了其大小

那么我们可以将当前物品『压缩大小』,放入背包中

假如当前的费用 图片说明 小于 图片说明 或者当前的费用 图片说明 小于 图片说明 ,我们可以把当前物品 强行 放进去,即让当前的 图片说明 或者让当前的 图片说明。这样我们是不是相当于只选择了一个物品?由于每个物品的 图片说明 都是正数,故在符合要求的前提下少选的 最优策略 一定比多选的最优策略 更优,故这样一定是最优的。
代码:
class Solution {
public:
    int f[2001][2001];
    int minCost(int breadNum, int beverageNum, vector<vector<int> >& packageSum) {
        memset(f,0x3f,sizeof f);//初始化一个很大的值
        f[0][0]=0;//边界
        for(int i=0;i<packageSum.size();i++){
            for(int j=breadNum;j>=0;j--){
                for(int k=beverageNum;k>=0;k--){
                    //max(j-packageSum[i][0],0)和 max(k-packageSum[i][1],0) 即把当前物品的费用压缩到j和k
                    f[j][k]=min(f[j][k],f[max(j-packageSum[i][0],0)][max(k-packageSum[i][1],0)]+packageSum[i][2]);
                }
            }
        }
        return f[breadNum][beverageNum];
    }
};

时间复杂度:图片说明 ,动态规划转移的过程中有3重循环,第一重是图片说明 的,第二重是图片说明 的,第三重是图片说明 的,故总的时间复杂度为图片说明
空间复杂度:图片说明 ,我们采用滚动数组将图片说明 优化到图片说明 ,这两维都是表示费用大小,故总的空间复杂度为图片说明

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务