背包问题变种:将数组分成两部分使得两部分的和的差最小

  
题目: 将一个数组分成两部分,不要求两部分所包含的元素个数相等,要求使得这两个部分的和的差值最小。比如对于数组{1,0,1,7,2,4},可以分成{1,0,1,2,4}和{7},使得这两部分的差值最小。

思路:差最小就是说两部分的和最接近,而且和所有数的和SUM的一半也是最接近的。假设用sum1表示第一部分的和,sum2表示第二部分的和,SUM表示所有数的和,那么sum1+sum2=SUM。假设sum1<sum2 那么SUM/2-sum1 = sum2-SUM/2; 
所以我们就有目标了,使得sum1<=SUM/2的条件下尽可能的大。也就是说从n个数中选出某些数,使得这些数的和尽可能的接近或者等于所有数的和的一般。这其实就是简单的背包问题了: 
背包容量是SUM/2. 每个物体的体积是数的大小,然后尽可能的装满背包。 
dp方程:f[i][V] = max(f[i-1][V-v[i]]+v[i], f[i-1][V] ) 
f[i][V]表示用前i个物体装容量为V的背包能够装下的最大值,f[i-1][V-v[i]]+v[i]表示第i个物体装进背包的情况,f[i-1][V]表示第i件物品不装进背包的情况。 

public static int match(int[] arr){
        int sum = Arrays.stream(arr).sum();
        int len = arr.length;
        int halfOfSum = sum/2;
        // 确定矩阵二维定义:第一维代表前i个物体,i可为0;第二维代表从0开始的连续容量值
        // 确定矩阵长宽,并初始化。因为矩阵第一维和第二维都是从0开始,所以要加一
        int matrix_firstDimensionLen = len+1;
        int matrix_secondDimensionLen = halfOfSum+1;
        int[][] matrix = new int[matrix_firstDimensionLen][matrix_secondDimensionLen];
        //初始化矩阵边界为0
        for (int i = 0; i < matrix[0].length; i++) {
            matrix[0][i] = 0;
        }
        for (int i = 0; i < matrix.length; i++) {
            matrix[i][0] = 0;
        }

        //arr的下标,是否与matrix的下标冲突:是的
        //matrix[i][j]定义:用前i个物体装容量为j的背包能够装下的最大值
        //arr[i]定义:第i+1个物体的大小,所以arr[i-1]才是第i个物体的大小
        //遍历从矩阵边界开始(不包括边界),所以i = 1, j = 1
        for (int i = 1; i < matrix_firstDimensionLen; i++) {
            for (int j = 1; j < matrix_secondDimensionLen; j++) {
                //如果第i件物体不装进背包
                matrix[i][j] = matrix[i-1][j];
                //如果第i件物体装进背包     //备注:j - arr[i-1] >= 0防止下标为负
                if(j - arr[i-1] >= 0 && matrix[i - 1][j - arr[i-1]] + arr[i-1]  > matrix[i][j]){
                    matrix[i][j] = matrix[i - 1][j - arr[i-1]] + arr[i-1];
                }
            }
        }
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                System.out.print(matrix[i][j] + "\t");
            }
            System.out.println("");
        }
        System.out.println(matrix[len][halfOfSum]);
        return  sum - matrix[len][halfOfSum]*2;
    }

public static void main(String[] args){
        int[] arr = {1,2,3,4,5};
        int value = match(arr);
        System.out.println(value);
}

 最后矩阵输出如下:

0	0	0	0	0	0	0	0	
0	1	1	1	1	1	1	1	
0	1	2	3	3	3	3	3	
0	1	2	3	4	5	6	6	
0	1	2	3	4	5	6	7	
0	1	2	3	4	5	6	7	
7
1

参考:http://blog.csdn.net/souldak/article/details/12354325

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
背包问题是经典的组合优化问题,主涉在给定的背包容量下,何选择物品放入背包,使得背包中物品的总价值最大化。背包问题可以分为0/1背包问题和包问题变种。 1. 01背包问题:在0/1背包问题中,每个物品要么完全放入背包,要么完全不放入背包。每个物品有一个对应的重量和价值,背包有一个固定的容量。目标是选择物品放入背包,使得背包中物品的总价值最大化,同时不能超过背包的容量。 一个常见的解决0/1背包问题的方法是使用动态规划。可以使用一个二维数组dp来记录每个状态下的最大价值。其中dp[i][j]表示在前i个物品中,背包容量为j时的最大价值。状态转移方程如下: ``` dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]) ``` 其中w[i]表示第i个物品的重量,v[i]表示第i个物品的价值。通过填充dp数组,最终dp[n][C]即为问题的解,其中n为物品的个数,C为背包的容量。 2. 背包问题变种背包问题还有一些变种,例如多重背包问题、无限背包问题和分数背包问题。 - 多重背包问题:在多重背包问题中,每个物品有一个对应的重量、价值和数量限制。目标是选择物品放入背包,使得背包中物品的总价值最大化,同时不能超过背包的容量,并且每个物品的数量不能超过其限制。 - 无限背包问题:在无限背包问题中,每个物品有一个对应的重量和价值,但是每个物品的数量是无限的。目标是选择物品放入背包,使得背包中物品的总价值最大化,同时不能超过背包的容量。 - 分数背包问题:在分数背包问题中,每个物品有一个对应的重量和价值,但是可以选择物品的一部分放入背包。目标是选择物品放入背包,使得背包中物品的总价值最大化,同时不能超过背包的容量。 以上是关于背包问题和其变种的简要介绍和解决方法。如果你有任何进一步的问题,请随时提问。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值