动态规划算法之分组问题(背包问题变形)-其一

本文介绍了如何将整数数组分成两组,使得两组元素之和的差值最小,通过将问题转化为背包问题,建立状态转移方程并实现代码。关键在于找到背包最大承重的一半,通过动态规划求解最终的差值。
摘要由CSDN通过智能技术生成

题目描述

给一个整数数组 array,把他分为两组 a 和 b,要使得 a 和 b 两组的元素之和的差最小,输出最小值(或者输出最小值的分组情况)

力扣上面第1049题也是该问题的一种变形问法1049. 最后一块石头的重量 II

问题分析

将一个数组分成两个,使两个数组的和之差最小,要想差最小,必然a组的和 b组的和 都趋近sum/2,换句话说,a组和在sum/2的左边逼近,b组和在sum/2的右边逼近。当然,a组的和逼近sum/2时,b组和也必然逼近。 我们把数字想象成石头,数字大小代表石头重量,a,b两组代表两个背包,所以,这个问题可以转化为在背包a的最大承重量为sum/2前提下,从原数组中拿取石头,使背包a所装的重量最大,即简化版的背包问题。

建立状态转移方程

f(i,target) 表示 轮到第i个石头选择时,背包最大空间为target时能获得的最大物品重量,

设数组weight[n]表示每个石头的重量,

则状态转移方程如下 f(i,target) = Max(f(i-1,target), f(i,target-weight[i])+weight[i])

f(i-1,target) 表示第i个物品不选时,能获得的最大重量

f(i,target-weight[i])+weight[i] 表示第i个物品选择时,能获得的最大重量

代码实现

 /**
     * @param stones 待分组的石头
     * @return a,b两组的最小差值
     */
    public int getMinSub(int[] stones) {
        if (stones == null || stones.length == 0) {
            return 0;
        }
        //石头总数
        int size = stones.length;
        //所有石头的总重量
        int sumWeight = 0;
        for (int temp : stones) {
            sumWeight = sumWeight + temp;
        }
        //所需背包的最大承受重量为所有石头总重量的一半
        int maxWeight = sumWeight / 2 + 1;
        //定义一个二维数组表示 轮到第i个石头选择时,背包最大承重为maxWeight时能装的石头最大总重量
        int[][] data = new int[size + 1][maxWeight];
        //从第一块石头开始遍历
        for (int i = 1; i <= size; i++) {
            //w代表背包的最大承受重量
            for (int w = 0; w < maxWeight; w++) {
                //第i个石头不选
                int temp1 = data[i - 1][w];
                int temp2 = 0;
                //第i个石头选了,选之前要先看背包放不放得下
                if (stones[i - 1] <= w) {
                    temp2 = data[i - 1][w - stones[i - 1]] + stones[i - 1];
                }
                //每块石头都可以选和不选,取最大值
                data[i][w] = Math.max(temp1, temp2);
            }
        }
        //a,b两组求差
        return Math.abs(sumWeight - data[size][maxWeight - 1] - data[size][maxWeight - 1]);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值