编程之美数组分割

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编程之美数组分割相关的知识,希望对你有一定的参考价值。

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

分析与解法

  从题目中可以分析出,题目的本质就是要从2n个整数中找出n个,使得它们的和尽可能地靠近所有整数之和的一半。

解法一:不靠谱的解法

  先将数组的所有元素排序,然后划分为S1 = {a1, a3, ..., a2n-1}和S2 = {a2, a4, ..., a2n};

  从S1和S2中找出一对数进行交换,使得两个集合中所有元素的和之间的差值尽可能的小,直到找不到可对换的。

  这种想法的缺陷是得到的S1和S2并一定总是最优的。

解法二:搜索

  假设2n个数之和的一半为target。我们要从2n个整数中找出n个元素的和,有三种可能:大于target、等于target和小于target。其中,大于和小于target这两种情况没有本质区别。因此,可以只考虑小于target的情况,而大于target的情况用来搜索中进行剪枝。

  用closestset来存放当前找到的最接近target的n个数,closestsum为这n个数的和。

  当搜索到n个数的和小于target且大于closestsum,则替换当前的最优解,直到搜索完毕。参考代码如下:

技术分享
 1 #include <iostream>
 2 #include <vector>
 3 using namespace std; 
 4 
 5 const int maxn = 10007; 
 6 int arr[maxn]; 
 7 int n, target, closestsum;
 8 vector<int> closestset; 
 9 
10 void dfs(vector<int> path, int cur, int sum)
11 {
12     if (path.size() == n/2)
13     {
14         if (sum > closestsum) 
15         {
16             closestset = path; 
17             closestsum = sum; 
18         }
19         return ; 
20     }
21     if (cur == n)
22     {
23         return ; 
24     }
25     for (int i = cur; i < n; i++)
26     {
27         sum += arr[cur]; 
28         if (sum <= target)
29         {
30             path.push_back(arr[cur]); 
31             dfs(path, i+1, sum); 
32             sum -= arr[cur]; 
33             path.pop_back(); 
34         }
35         else 
36         {
37             sum -= arr[cur]; 
38         }
39     }
40 }
41 
42 int main(int argc, char *argv[])
43 {
44     while (cin >> n)
45     {
46         if (n % 2) 
47         {
48             cout << "enter an even number please:\\n"; 
49             continue; 
50         }
51         target = 0, closestsum = 0; 
52         closestset.clear(); 
53         for (int i = 0; i < n; i++)
54         {
55             cin >> arr[i]; 
56             target += arr[i]; 
57         }
58         target /= 2; 
59         vector<int> path; 
60         int sum = 0, cur = 0;
61         dfs(path, cur, sum); 
62         cout << target << " " << closestsum << endl; 
63     }
64 }
View Code

  时间复杂度为O(2n)。

 

以上是关于编程之美数组分割的主要内容,如果未能解决你的问题,请参考以下文章

编程之美寻找数组中的最大值和最小值

编程之美求数组的子数组之和的最大值

编程之美快速寻找满足条件的两个数

编程之美 2.18数组分割

《编程之美》区间重合判断的一些思考

编程之美----字符串移位包含的问题