LeetCode 1049. 最后一块石头的重量 II(很抽象的思维,01背包)

题意:
有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。
那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 01 <= stones.length <= 30
1 <= stones[i] <= 100
解法:
令d[i][j]表示前i个石头能否合并为一个大小为j的石头.
边界为d[0][0]=1.

转移:
设当前为d[i][j],有一个石头p,
1.如果j和p合并,那么d[i+1][max(j,p)-min(j,p)]=1;
2.如果j和p不合并,那么可以看作是有一个j+p的大石头,d[i+1][j+p]=1,


为什么可以看作是j+p呢,因为这样对之后的操作没有影响:
假设我们有石头a和b,不合并的话就变为(a+b),
如果这时候新加入一个石头c:
1.(a+b)<=c,那么显然可以操作出一个c-(a+b)的石头,不影响.
2.(a+b)>c,我们如果能操作出一个(a+b)-c的石头,那么就能证明不影响,
如果a>=c或b>=c,那么就可以操作出(a-c)+b或者a+(b-c),即a+b-c,不影响,
如果a<c且b<c,此时先将a,b,c变成c-a,b,0,然后变成0,b-(c-a),0,即有了a+b-c,也不影响.

dp完之后从小到大枚举j,若d[n][j]=1,return j.
code:
const int maxm=3e3+5;
int d[33][maxm];
class Solution {
public:
    int lastStoneWeightII(vector<int>& a) {
        int n=a.size();
        int s=0;
        for(auto i:a)s+=i;
        for(int i=0;i<=n;i++)for(int j=0;j<=s;j++)d[i][j]=0;
        d[0][0]=1;
        for(int i=0;i<n;i++){
            int p=a[i];
            for(int j=0;j<=s;j++){
                if(!d[i][j])continue;
                d[i+1][j+p]=1;
                d[i+1][max(p,j)-min(p,j)]=1;
            }
        }
        for(int j=0;j<=s;j++)if(d[n][j])return j;
        return -1;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值