[编程之美] PSet2.18 数组分割
来源:互联网 发布:linux支持的处理器 编辑:程序博客网 时间:2024/05/22 05:17
参考:http://blog.csdn.net/linyunzju/article/details/7729774
问题描述:
有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为两个子数组,子数组的元素个数不限,并使两个子数组之和最接近。
分析与思路:
从题目中可以看出,题目的本质就是从2n个整数中找出n个,使得它们的和尽可能靠近所有整数之和的一半。
解法一:
这个问题存储的是从前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]的值作为下标存储起来,将这个最优问题转化为判定问题,用带动态规划的思想的递推法来解。
代码如下:
//数组分割:(2n个数组中分成两半让各组之和最接近)//使用dp[i][s]来标记能否找到i个数,使他们之和为s//递推过程为dp[i][s]=dp[i-1][s]或dp[i-1][s-Arr[i]],复杂度O(N^2*Sum)#define MIN(a,b) ((a)>(b)?(b):(a))const int MAXLEN = 100;const int MAXSUM = 1000;int ArrPartition(int Arr[] , int arrLen ){//---判断输入数组是否为偶数大小if(arrLen & 1)return -1;//---对数组求和int sum = 0;for(int i=0 ; i<arrLen ; i++)sum += Arr[i];//---定义判决数组dpbool dp[MAXLEN][MAXSUM];memset(dp,0,sizeof(dp));dp[0][0] = true;//---动态规划求解判决数组for(int i=1 ; i<=arrLen ; i++){//对于第i个数for(int j=MIN(i,arrLen/2) ;j>=1; j--)//i个数中取j个数,j的范围为[i,arrLen/2],由递推公式可知要自底向上求解for(int v=1 ; v<=sum/2 ; v++){if(v>=Arr[i-1] && dp[j-1][v-Arr[i-1]])//Arr下标从0开始,与dp下标从1开始不同。dp[j][v] = true;}}int s;for (s=sum/2; s>=1 ; s--)if(dp[arrLen/2][s])break;return sum/2-s;}
0 0
- [编程之美] PSet2.18 数组分割
- [编程之美] PSet2.13 子数组的最大乘积
- [编程之美] PSet2.17 数组循环移位
- [编程之美] PSet2.7 最大公约数问题
- 编程之美 数组分割
- 编程之美-数组分割
- 《编程之美》数组分割
- 编程之美 - 数组分割
- [编程之美] PSet2.14 求数组的子数组之和的最大值
- [编程之美] PSet2.10 寻找数组中的最大值和最小值
- [编程之美] PSet2.15 子数组之和的最大值(二维)
- [编程之美] PSet2.16 求数组中最长的递增子序列
- 编程之美之数组分割
- 编程之美读书笔记_2.18 数组分割
- 编程之美;数组分割DP;
- 《编程之美》 2.18 数组分割
- DP 数组分割《编程之美》
- 编程之美 2.18 数组分割
- This function or variable may be unsafe
- Codeforces Round #260 (Div. 2) (DP没学好。。)
- C语言符号优先级
- Eclipse常用快捷键使用
- ListView嵌套GridView使用详解及注意事项
- [编程之美] PSet2.18 数组分割
- IOS 字符串中去除特殊符号
- php常见问题解决
- install qt on ubuntu 14.04
- 程序开发学习方法之易犯错误
- 用链表实现约瑟夫环
- Xcode及模拟器SDK下载
- java基础-面向对象、类与对象的定义
- Android游戏开发第三天(1)