博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编程之美:数组分割
阅读量:6684 次
发布时间:2019-06-25

本文共 2277 字,大约阅读时间需要 7 分钟。

题目概述:有一个没有排序,元素个数为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) }
按照这个递推公式来计算,最后找出集合S(2N, N)中与SUM最接近的那个和,这便是答案。
因为这个过程中只关注和不大于SUM/2的那个子数组的和。所以集合中重复的和以及大于SUM/2的和都是没有意义的。把这些没有意义的和剔除掉,剩下的有意义的和的个数最多就是SUM/2个。所以,我们不需要记录S(2N,N)中都有哪些和,只需要从SUM/2到1遍历一次逐个询问这个值是不是在S(2N,N)中出现,第一个出现的值就是答案。

例子:

比如说有一个6个数的数组,分成两个数组,其中每个数组有3个数:

[2,5,7,9,11,13]

计算可得:SUM=47,SUM/2=23.5

我们需要求的是:

k=6,i=3时,套入上面公式可得:

S(6,3)=S(5,3) U {13+{S(5,2)}}

集合S(5,3)={14,16,18,20,22,21,23,25,27}

集合S(5,2)={7,9,11,12,13,14,16,18,20}

13+S(5,2)={20,22,24,25,26,27,29,31,33}

最后:

S(6,3)={14,16,18,20,21,22,23,24,25,26,27,29,31,33}

我们在集合S(6,3)中,从SUM/2(23.5)到1遍历一次,逐个询问这个值是不是在S(6,3)中出现,第一个出现的值就是答案,也就是23,即答案。

 

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;              }          }      }  }

 

转载地址:http://iyaao.baihongyu.com/

你可能感兴趣的文章
MySQL大表优化方案
查看>>
文件 / I/O重定向 / 用户和用户组
查看>>
iOS开发的插件和工具
查看>>
IOS开发之----Category的使用
查看>>
设置UIButton,UITextFild边框圆角(上半边或下半边)
查看>>
Python __init__.py 文件使用
查看>>
Spring源码-IOC容器(五)-Bean的初始化
查看>>
zookeeper原理
查看>>
我的友情链接
查看>>
有监视哨的顺序查找
查看>>
微信小程序开发之表单验证(WxValidate使用)
查看>>
Oracle DataBase 各种版本资源路径汇总
查看>>
linux文件中的目录的理解
查看>>
openstack运维实战系列(十八)nova与ceph结合
查看>>
我的友情链接
查看>>
高质量的C代码.释放内存
查看>>
C++static成员函数和static成员的学习
查看>>
缓存名称服务器
查看>>
switch3 STP、RSTP
查看>>
IPv6路由协议
查看>>