(转)数组分割问题

转自:http://blog.csdn.net/imzoer/article/details/7436323

问题详见:编程之美

思路:

01背包问题变形

假设数组A[1..2N]所有元素的和是SUM。

模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合。

显然:

S(k, 1) = {A[i] | 1<= i <= k}

S(k, k) = {A[1]+A[2]+…+A[k]}

S(k, i) = S(k-1, i) U {A[k] + x | x属于S(k-1, i-1) }

他人代码:

public class Main {

    public static void main(String[] args) {
        int A[] = { 1, 2, 3, 5, 7, 8, 9 };
        // int A[] = { 1, 5, 7, 8, 9, 6, 3, 11, 20, 17 };
        func(A);
    }

    static void func(int A[]) {
        int i;
        int j;

        int n2 = A.length;
        int n = n2 / 2;
        int sum = 0;
        for (i = 0; i < A.length; i++) {
            sum += A[i];
        }

        /**
         * flag[i][j]:任意i个数组元素之和是j,则flag[i][j]为true
         */
        boolean flag[][] = new boolean[A.length + 1][sum / 2 + 1];
        for (i = 0; i < A.length; i++)
            for (j = 0; j < sum / 2 + 1; j++)
                flag[i][j] = false;

        flag[0][0] = true;

        for (int k = 0; k < n2; k++) {
            for (i = k > n ? n : k; i >= 1; i--) {
                // 两层外循环是遍历集合S(k,i)
                for (j = 0; j <= sum / 2; j++) {
                    if (j >= A[k] && flag[i - 1][j - A[k]])
                        flag[i][j] = true;
                }
            }
        }
        for (i = sum / 2; i >= 0; i--) {
            if (flag[n][i]) {
                System.out.println("sum is " + sum);
                System.out.println("sum/2 is " + sum / 2);
                System.out.println("i is " + i);
                System.out.println("minimum delta is " + Math.abs(2 * i - sum));
                break;
            }
        }
    }
}

学习之处:

  • 对于判断一个元素要还是不要,要了它对总体的结果有没有影响,它的存在是否由意思,考虑用01背包问题解决
  • 现在刷题有了一定的数量了,基本常见的数据结构和算法也都有了了解,知识范围也就那么大,遇到问题要像是否接触过类似的问题,善于总结,归纳和思考。
时间: 2024-08-29 19:46:11

(转)数组分割问题的相关文章

【编程之美】数组分割

有一个无序.元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近? 分析与解法 从题目中可以分析出,题目的本质就是要从2n个整数中找出n个,使得它们的和尽可能地靠近所有整数之和的一半. 解法一:不靠谱的解法 先将数组的所有元素排序,然后划分为S1 = {a1, a3, ..., a2n-1}和S2 = {a2, a4, ..., a2n}: 从S1和S2中找出一对数进行交换,使得两个集合中所有元素的和之间的差值尽可能的小,直到找不到可对换的.

数组分割问题(转)

题记:这道题和<编程之美>一书中2.18节的数组分割区别不大,但本人觉得<编程之美>这一节讲的不够透彻,不好理解(或许本人愚钝),故给出自己的思路,同时也给出打印其中一种方案的方法(这一点<编程之美>并没有提到). 两个序列大小均为n,序列元素的值为任一整数,无序: 要求通过交换两个序列的元素,使序列a元素之和与序列b的元素之和的差最小(可能存在很多种组合,要求找出其中一种即可). 如序列:1  5   7   8   9和序列6  3   11  20  17我们可以

数组分割问题

昨天同学问我一道关于数组分割的问题——有一个无序.元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并是两个子数组的和最接近. 假设2n个整数之和为sum.从2n个整数中找出n个元素的和,有三种可能:大于sum/2,等于sum/2,小于sum/2.可以考虑小于等于sum/2的情况.使用动态规划解决这个问题,其实这是一个NP问题,只能尽量去接近sum/2这个值. 我们可以定义dp[k][s]代表从前k个数中去任意个元素,且k小于等于n,其和为s是否存在:之所以将选出的

数组分割问题(转载)

问题: 1. 有一个无序.元素个数为2n的正整数数组,要求:如何能把这个数组分割为两个子数组,子数组的元素个数不限,并使两个子数组之和最接近. 2. 有一个无序.元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组之和最接近. 分析: 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合.显然:                S(k, 1) = {A[i] | 1<= i

[经典面试题][网易]数组分割

[题目] 任意2N个正整数,从其中选出N个整数,使得选出的N个整数和同剩下的N个整数之和的差最小. [来源] 网易 [分析] 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略. 从2N个数中找N个元素,有三种可能:大于Sum/2,小于Sum/2以及等于Sum/2.而大于Sum/2与小于等于Sum/2没区别,故可以只考虑小于等于Sum/2的情况. 令S(k, i)表示前k个元素中任意i个元素的和的集合.显然: S(k, 1) = {A[i] | 1<= i <=

数组分割——解题笔记

数组分割--解题笔记 题目:有一个没有排序.元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近. 分析:这道题目可以用动态规划求解,或者说是一个典型的0,1背包问题,对于第i的数,到底是放进去还是不放,就要看放了对结果有什么影响,不放对结果又有什么影响.而结果是依据题目而言的,这道题目中的结果就是数组之和. 注意,一般动态规划数组中,需要先初始化所有i的结果,初始化可以为1,或者0. 然后,从前往后,依次得到每个i的优化结果,而且需要注意的是

编程之美2.18 数组分割 原创解O(nlogn)的时间复杂度求解:

题目:有一个无序.元素个数为2n的正整数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近? 1 1 2 -> 1 1 vs  2 看题时,解法的时间复杂度一般都大于或等于O(n^2).突然灵感一闪,发现一个新的解法,应该算是一个动态规划的过程吧,思路比较简单,请看代码.空间复杂度O(nlogn),时间复杂度O(n).但是不能确定是否适用所有正整数组,如果有错,请给出你的测试用例,谢谢! 代码如下: 1 1 #include <iostream> 2 2 #

算法之--数组分割

题目来源:编程之美2.18 有一个无序的,元素个数为2n的正整数的数组,要求: 如何能把这个数组分割为元素个数为n的两个数组,使得两个子数组的和尽量接近. 解析:因为两个子数组的和是一定的,等于整个数组的和.现在要求使得两个字数组的和尽量的接近,也就意味着要从其中选出n个数使得这n个数的和尽可能的接近sum/2,不妨设为从小于sum/2的方向接近.于是,这就是一个01背包的问题: 现在有2N个物品,每个物品的重量为A[i],有一个背包的大小为sum/2,现在从中挑选出N个物品,使得背包尽可能的被

编程之美2.18—数组分割

题目: 有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近. 基本思想: 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合. 显然: S(k, 1) = {A[i] | 1<= i <= k} S(k, k) = {A[1]+A[2]+-+A[k]} S(k, i) = S(k-1, i) U {A[k] + x | x属于S(k-1, i-1) }

编程之美——数组分割

一.题目概述:有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近.假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合.显然:S(k, 1) = {A[i] | 1<= i <= k}S(k, k) = {A[1]+A[2]+…+A[k]}S(k, i) = S(k-1, i) U {A[k] + x | x属于S(k-1, i-1) }按照这个递推公式来