数组分割问题

  昨天同学问我一道关于数组分割的问题——有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并是两个子数组的和最接近。

  假设2n个整数之和为sum。从2n个整数中找出n个元素的和,有三种可能:大于sum/2,等于sum/2,小于sum/2。可以考虑小于等于sum/2的情况。使用动态规划解决这个问题,其实这是一个NP问题,只能尽量去接近sum/2这个值。

  我们可以定义dp[k][s]代表从前k个数中去任意个元素,且k小于等于n,其和为s是否存在;之所以将选出的数之和放在下标中,而不是作为dp[k]的值,是因为那种做法不满足动态规划的前提——最优化原理。

  

#include <iostream>
#include <mem.h>
using namespace std;
const int MaxN = 100;
const int maxSum = 100000;
bool dp[MaxN][maxSum];
int A[MaxN];
int main()
{
    int n, k, i, s;
    cin >> n;
    for(i = 1; i <= 2*n; i++)
    {
        cin >> A[i];
    }
    int sum = 0;
    for(i = 1; i <= 2*n; i++)
        sum += A[i];
    memset(dp, false, sizeof(dp));
    dp[0][0] = true;
    for(k = 1; k <= 2*n; k++)
    {
        for(i = min(k, n);i >= 1; i--)
        {
            for(s = 1; s <= sum/2; s++)
            {
                if(s >= A[k] && dp[i-1][s-A[k]])
                    dp[i][s] = true;
            }
        }
    }
    for(s = sum/2; s >= 1 && !dp[n][s]; s--);
    cout << "s1 = " << s << ";" << "s2 = " << sum - s << endl;
    return 0;
}
时间: 2024-10-13 08:51:44

数组分割问题的相关文章

【编程之美】数组分割

有一个无序.元素个数为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我们可以

数组分割问题(转载)

问题: 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) }按照这个递推公式来