Leetcode刷题:最后一块背包的重量

(1)暴力搜索+回溯解法:(时间复杂度过高,超时)

class Solution {
public:
    int ans=100; 
    int lastStoneWeightII(vector<int>& stones) {
        shatter(stones);
        return ans;
    }
    void shatter(vector<int>& stones){
        if(stones.empty()){
            ans=0;return;
        }
        else if(stones.size()==1){
            if(stones[0]<ans)
                ans=stones[0];
            return;
        }   
        for(int i=0;i<(stones.size()-1);i++){
            int iNum=stones[i];
            for(int j=i+1;j<stones.size();j++){
                int jNum=stones[j];
                //从数组中粉碎 i j石头
                if(stones[i]==stones[j]){
                    stones.erase(stones.begin()+j);
                    stones.erase(stones.begin()+i);
                }else if(stones[i]<stones[j]){
                    stones[j]=jNum-iNum;
                    stones.erase(stones.begin()+i);
                    
                }else{
                    stones[i]=iNum-jNum;
                    stones.erase(stones.begin()+j);
                }
                //对新数组进行处理
                shatter(stones);
                //回溯 把 i j个元素放回去
                if(iNum==jNum){
                    stones.insert(stones.begin()+i,iNum);
                    stones.insert(stones.begin()+j,jNum);
                }else if(iNum<jNum){
                    stones.insert(stones.begin()+i,iNum);
                    stones[j]=jNum;
                }else{
                    stones[i]=iNum;
                    stones.insert(stones.begin()+j,jNum);
                }
                
            }
        }
    }
};

(2)动态规划法

可以深入理解一下,如果能把所有石头分为大小最接近的两堆W_{P1}W_{P2}W_{P1}+W_{P2}=W_{sum}\wedge \left \|W_{P1}-W_{P2} \right \|==Min,则取到的Min值为问题的解。假设W_{P1}<W_{P2},有W_{P1}<=\frac{W_{sum}}{2}Min=W_{sum}-2\times W_{P1}。这样就把问题转化成求解在石头中选取总重量<=且最接近\frac{W_{sum}}{2}W_{P1}的背包问题。对于每个石头,有选入背包P_{1}和不选(入P_{2})两种操作。

假设solution[i][j][s]为从第i到第j个石头中得到总重量为s的背包问题是否有解,最开始i=0,j=n,s=0。随着求解问题的逐步深入我们可知:

(1)当石头j+1的重量>s时,不可选它入背包P_{1}中,即solution[i][j+1][s]=solution[i][j][s]

(2)否则,可考虑把j+1块石头选入背包P_{1},但是需要考虑,选它的前提是能否在前面的石头中选到总重量为s-W_{j+1}的石头。即:

       i.如有solution[i][j][s-W_{j+1}],则可以选择石头j+1。

       solution[i][j+1][s]=solution[i][j][s-W_{j+1}]

       ii.否则,solution[i][j+1][s]=solution[i][j][s]

       iii.在实际写代码时,可以对上面的逻辑进行适当的简化,已知solution[][][]是个bool值,则(2)可合并为solution[j+1][s]=solution[j][s]\left | \right |solution[j][s-W_{j}](把i设为固定值0)

 

最开始j=0,s=0且s<=\frac{W_{sum}}{2},solution[0][0]=true。当solution[j][s]=true且s为接近\frac{W_{sum}}{2}的最大值时,Min=W_{sum}-s*2

代码为:

class Solution {
public: 
    int lastStoneWeightII(vector<int>& stones) {
        int sum = accumulate(stones.begin(), stones.end(), 0);
        int n = stones.size(), m = sum /2;
        vector<vector<int>> dp(n + 1, vector<int>(m+1));
        dp[0][0]=true;
        for(int j=0;j<n;++j){
            for(int s=0;s<=m;++s){
                if(stones[j]>s){
                    dp[j+1][s]=dp[j][s];
                }else{
                    dp[j+1][s]=dp[j][s]||dp[j][s-stones[j]];
                }
            }
        }
        for(int j=m;;j--){
            if(dp[n][j])
               return sum - 2 * j;
        }
    }
};

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值