题解 | #牛能和牛可乐的礼物#

牛能和牛可乐的礼物

http://www.nowcoder.com/practice/6c5c3a9901ec4a90aa140348243da4e8

方法1 暴力求解

看到题目第一想法,每个礼物选或者不选有两条分支。因为我们希望尽量把礼物均分,所以要求累计价值不超出总价值的一半,否则将执行剪枝。如果出现正好均分的方案后,将flag置1,跳过后续遍历分支的步骤。当所有分支走完,找一个总价值最接近一半的方案。

很遗憾,暴力求解的方案虽然已经做了一定的剪枝操作,但在数据量多了之后仍会超时,用例通过69.23%。

function maxPresent( presentVec ) {
    let all = eval(presentVec.join("+"))
    let max =0
    let flag = 0
    choose(presentVec,0,0)
    function choose(presentVec,i,sum){
        if(flag==1)return
        if(i<presentVec.length){
            choose(presentVec,i+1,sum)
            if((sum+presentVec[i])<=all/2){
                choose(presentVec,i+1,sum+presentVec[i])
                max = Math.max(max,sum+presentVec[i])
                if(max==all/2){
                    flag=1
                    return
                }
            }
        }
    }
    return Math.abs(all-2*max)
}
module.exports = {
    maxPresent : maxPresent
};

方法2 动态规划

结合暴力破解的思路,每一个礼物选或者不选,其实很像0/1背包问题。现在的背包空间变成了总价值的一半,我们目标是尽量放满背包,使得总价值量最大。题目备注中的“单个礼物价值不超过100,礼物个数小于100,所有礼物总价值不超过10000”其实也在引导我们使用dp数组进行解题。

新手做动态规划的题目最迷茫的就是,我们应该怎样使用dp数组?或者说我们需要用dp数组的每一个空间表示什么样的含义?

我们可以用dp表示,最多只能拿i价值的礼物,实际拿到的最多的礼物价值dp[i].这样我们可以再利用每个物品的价值,去建立dp空间之间的联系。

例如[1,2,3,4],总价值量sum为10,因为希望尽量均分,所以我们只用开0-5的对应数组[0,0,0,0,0,0],其中dp[5]就表示最多拿价值和为5的礼物组合,实际能拿到的最大价值量。

我们顺着每个礼物来看,引入第一件礼物(价值为1)时,dp就变成了[0,1,1,1,1,1],表示可拿价值上限大于等于1时,实际最大价值量都为这第一件物品的价值。

引入第二件物品(价值为2)时,dp就变成了[0,1,2,3,3,3],表示可拿价值上限大于等于1时,实际价值最多为1;可拿价值上限大于等于2时,实际价值最多为2;可拿价值上限大于等于3时,实际价值最多为3(因为目前我们只引入了两件礼品)

引入第三件物品(价值为3)时,dp就变成了[0,1,2,3,4,4]

引入第四件物品(价值为4)时,dp就变成了[0,1,2,3,4,5]

最终差值即为总价值量sum-2*dp数组的最后一位

function maxPresent( presentVec ) {
    if(presentVec.length==0)   return 0
    let sum = eval(presentVec.join('+'))
    let dp = new Array(Math.floor(sum/2)+1).fill(0)
    //dp[i]表示设定价值总量上限i时,实际能获得的最大物品价值总量,
    //因为我们希望尽量均分,所以只需要开一半总量的dp空间
    //比如实例1[1,2,3,4],sum为10,我们需要开0-5也就是6个空间的dp
    for(let i = 0;i<presentVec.length;i++){
        for(let j = dp.length-1;j>=presentVec[i];j--){
            dp[j]=Math.max(dp[j],dp[j-presentVec[i]]+presentVec[i])
            //对于每一个presentVec中的物品,我们调整价值总量上限大于等于这个物品价值的dp空间,否则总量不够也加不进来
            //比较dp[j]和dp[j-presentVec[i]]+presentVec[i],选择价值量更大的组合
        }
    }
    return sum-2*dp[dp.length-1]
}
module.exports = {
    maxPresent : maxPresent
};

alt

全部评论

相关推荐

01-07 15:50
四川大学 Java
看日出看日落:好好背八股,做算法。我身边跟你bg差不多的基本都大厂暑期
点赞 评论 收藏
分享
小狗吃臭臭:以后用不到你设计的手机了,可惜!
点赞 评论 收藏
分享
评论
6
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务