问题

1. 有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为两个子数组,子数组的元素个数不限,并使两个子数组之和最接近。

2. 有一个无序、元素个数为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最接近的那个和,这便是答案。这个算法的时间复杂度是O(2^N).
          因为这个过程中只关注和不大于SUM/2的那个子数组的和。所以集合中重复的和以及大于SUM/2的和都是没有意义的。把这些没有意义的和剔除掉,剩下的有意义的和的个数最多就是SUM/2个。所以,我们不需要记录S(2N,N)中都有哪些和,只需要从SUM/2到1遍历一次,逐个询问这个值是不是在S(2N,N)中出现,第一个出现的值就是答案。我们的程序不需要按照上述递推公式计算每个集合,只需要为每个集合设一个标志数组,标记SUM/2到1这个区间中的哪些值可以被计算出来。

1、解法

由于对两个子数组和最接近的判断不太直观,我们需要对题目进行适当转化。我们知道当一个子数组之和最接近原数组之和sum的一半时,两个子数组之和是最接近的。所以转化后的题目是:从2n个数中选出任意个数,其和尽量接近于给定值sum/2

这个问题存储的是从前k个数中选取任意个数,且其和为s的取法是否存在dp[k][s]。之所以将选出的数之和放在下标中,而不是作为dp[k]的值,是因为那种做法不满足动态规划的前提——最优化原理,假设我们找到最优解有k个数p1p2...pk(选出的这k个数之和是最接近sum/2的),但最优解的前k-1个数p1p2...pk-1之和可能并不是最接近sum/2的,也就是说可能在访问到pk之前有另一组数q1q2....qk-1其和相比p1p2...pk-1之和会更接近sum/2,即最优解的子问题并不是最优的,所以不满足最优化原理。因此我们需要将dp[k]的值作为下标存储起来,将这个最优问题转化为判定问题,用带动态规划的思想的递推法来解。

外阶段:在前k1个数中进行选择,k1=1,2...2*n。
       内阶段:从这k1个数中任意选出k2个数,k2=1,2...k1。

状态:这k2个数的和为s,s=1,2...sum/2。

决策:决定这k2个数的和有两种决策,一个是这k2个数中包含第k1个数,另一个是不包含第k1个数。

dp[k][s]表示从前k个数中取任意个数,且这些数之和为s的取法是否存在。

 1 #include <iostream>
 2 #include <algorithm>
 3
 4 using namespace std;
 5
 6 #define MAXN 101
 7 #define MAXSUM 100000
 8 int A[MAXN];
 9 bool dp[MAXN][MAXSUM];
10
11 // dp[k][s]表示从前k个数中去任意个数,且这些数之和为s的取法是否存在
12 int main()
13 {
14     int n, i, k1, k2, s, u;
15     cin >> n;
16     for (i=1; i<=2*n; i++)
17         cin >> A[i];
18     int sum = 0;
19     for (i=1; i<=2*n; i++)
20         sum += A[i];
21     memset(dp,0,sizeof(dp));
22     dp[0][0]=true;
23     // 外阶段k1表示第k1个数,内阶段k2表示选取数的个数
24     for (k1=1; k1<=2*n; k1++)            // 外阶段k1
25     {
26         for (k2=k1; k2>=1; k2--)        // 内阶段k2
27             for (s=1; s<=sum/2; s++)    // 状态s
28             {
29                 //dp[k1][s] = dp[k1-1][s];
30                 // 有两个决策包含或不包含元素k1
31                 if (s>=A[k1] && dp[k2-1][s-A[k1]])
32                     dp[k2][s] = true;
33             }
34     }
35     // 之前的dp[k][s]表示从前k个数中取任意k个数,经过下面的步骤后
36     // 即表示从前k个数中取任意个数
37     for (k1=2; k1<=2*n; k1++)
38         for (s=1; s<=sum/2; s++)
39             if (dp[k1-1][s])
40                 dp[k1][s]=true;
41     // 确定最接近的给定值sum/2的和
42     for (s=sum/2; s>=1 && !dp[2*n][s]; s--)
43                ;
44
45     printf("the differece between two sub array is %d\n", sum-2*s);
46 }

2. 解法

但本题还增加了一个限制条件,即选出的物体数必须为n,这个条件限制了内阶段k2的取值范围,并且dp[k][s]的含义也发生变化。这里的dp[k][s]表示从前k个数中取任意不超过n的k个数,且这些数之和为s的取法是否存在。

 1 #include <iostream>
 2 #include <algorithm>
 3
 4 using namespace std;
 5
 6 #define MAXN 101
 7 #define MAXSUM 100000
 8 int A[MAXN];
 9 bool dp[MAXN][MAXSUM];
10
11 // 题目可转换为从2n个数中选出n个数,其和尽量接近于给定值sum/2
12 int main()
13 {
14     int n, i, k1, k2, s, u;
15     cin >> n;
16     for (i=1; i<=2*n; i++)
17         cin >> A[i];
18     int sum = 0;
19     for (i=1; i<=2*n; i++)
20         sum += A[i];
21     memset(dp,0,sizeof(dp));
22     dp[0][0]=true;
23     // 对于dp[k][s]要进行u次决策,由于阶段k的选择受到决策的限制,
24     // 这里决策选择不允许重复,但阶段可以重复,比较特别
25     for (k1=1; k1<=2*n; k1++)                // 外阶段k1
26         for (k2=min(k1,n); k2>=1; k2--)        // 内阶段k2
27             for (s=1; s<=sum/2; s++)    // 状态s
28                 // 有两个决策包含或不包含元素k1
29                 if (s>=A[k1] && dp[k2-1][s-A[k1]])
30                     dp[k2][s] = true;
31     // 确定最接近的给定值sum/2的和
32     for (s=sum/2; s>=1 && !dp[n][s]; s--);
33     printf("the differece between two sub array is %d\n", sum-2*s);
34 }

载自:http://blog.csdn.net/tianshuai1111/article/details/7828907

转载于:https://www.cnblogs.com/suiyuanjianke/p/5305460.html

数组分割问题(转载学习)相关推荐

  1. 2021-01-24过去十年十大AI研究热点,分别为深度神经网络、特征抽取、图像分类、目标检测、语义分割、表示学习、生成对抗网络、语义网络、协同过滤和机器翻译。

    专利申请量全球第一!清华人工智能发展报告:国内215所高校成立相关本科专业 发布时间:01-2415:20万象大会年度获奖创作者,东方财富网官方帐号 1月20日,清华大学人工智能研究院.清华-中国工程 ...

  2. 数组分割问题——另一种方法

    http://blog.csdn.net/lengzijian/article/details/7842551 还需要验证 最近一直看编程之美,想法真的很重要,今天发这篇文章还是有一点不自信,希望碰到 ...

  3. 程序员面试100题之十五:数组分割

    一.题目概述:有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近. 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的 ...

  4. 武汉大学 RSIDEA 团队开源LoveDA:可同时推进语义分割和迁移学习

    关注公众号,发现CV技术之美 本文分享论文『LoveDA: A Remote Sensing Land-Cover Dataset for Domain Adaptive Semantic Segme ...

  5. 语义分割——DeepLabv3+的学习笔记~

    1 前言 听说DeepLabv3+是现在最优秀的语义分割框架~ 2 学习笔记 2.1 DeepLabv3+用到了CRF的技术吗? 没有,好像是通过增加context模块实现的:也就是利用了上下文的信息 ...

  6. Java中如何将一个数组分割成多个等长度的数组

    Java中如何将一个数组分割成多个等长度的数组,最后剩下的为一个素组 先看图 分析数据 提取公式 分装代码 1.如下我们需求 最近朋友android项目中有一个需求如下: 这一个长集合[item0, ...

  7. paddlepaddle 7 面向语义分割的迁移学习

    正常的迁移学习(迁移自建网络)使用方法如paddlepaddle 6 使用迁移学习对图像进行分类_a486259的博客-CSDN博客,但需要使用Deeplab.HRNet.UNET,FCN等知名的开源 ...

  8. 将MNIST手写数字数据集导入NumPy数组(《深度学习入门:基于Python的理论与实现》实践笔记)

    将MNIST手写数字数据集导入NumPy数组(<深度学习入门:基于Python的理论与实现>实践笔记) 一.下载MNIST数据集(使用urllib.request.urlretrieve( ...

  9. php 数组分割,php 数组分割的方法

    在 php 编程中,如果遇到数组的元素过多,不方便处理的情况下.我们可以通过分割数组的方法,将其变成一个个的小数组块,这样再处理就方便很多了. php 中预设了一个 array_chunk() 函数, ...

  10. 数组存储与指针学习笔记(三)指针与数组

    嵌入式C语言学习进阶系列文章 GUN C编译器拓展语法学习笔记(一)GNU C特殊语法部分详解 GUN C编译器拓展语法学习笔记(二)属性声明 GUN C编译器拓展语法学习笔记(三)内联函数.内建函数 ...

最新文章

  1. 基于springMVC拦截器实现操作日志统计
  2. ovation系统服务器安装,Ovation系统介绍.ppt
  3. android 快传 源码_最新安卓仿茄子快传APP源码包括服务端源码Android开发快传类项目源码全套...
  4. java中哲学家就餐死锁_哲学家就餐问题与死锁总结
  5. SpringBoot2 集成日志,复杂业务下的自定义实现
  6. Appium+Python API相关知识了解
  7. 【tips】编译epic异常解决
  8. OSChina 周二乱弹 ——有时醒来发现身边是不同的姑娘
  9. ArcGIS制图表达Representation-符号制作
  10. 英国科研学术网络Janet遭遇DDoS攻击
  11. IDEA中使用JUnit---java测试类
  12. VC2005编译优化选项之玄机
  13. 小米笔记本网卡驱动失效,无法联网
  14. centos系统下安装daemontools详细指南
  15. 方程检验格式图片_eviews的异方差检验ppt课件
  16. 基于c语言编程思路的实践与探索,基于C语言编程思路的实践与探索
  17. 谷歌动态验证码二次验证ssh
  18. TM4C123G学习记录(2)--GPIO
  19. Java读取word模板,并动态生成word
  20. 高通平台开发系列讲解(外设篇)高通Camera软件架构

热门文章

  1. 从 0 开始机器学习 - 机器学习算法诊断
  2. 天池NLP文本分类比赛如何轻松轻松获得Top K的秘诀!
  3. 【面试经验】关于BERT,面试官们都怎么问
  4. 4.1 API : MultinomialNB、GaussianNB、BernoulliNB
  5. 统计学习方法读书笔记8-朴素贝叶斯
  6. 李宏毅机器学习——无监督学习(三)
  7. 30+岁、没转管理、加不动班,我的竞争力从哪里来?
  8. 用GPU进行TensorFlow计算加速
  9. 每周荐书:SLAM、Vue2、爬虫(评论送书)
  10. 8.15 SNAIL:神经注意力元学习