动态规划实例(十四):划分问题
来源:互联网 发布:默沙东临床数据管理员 编辑:程序博客网 时间:2024/06/05 11:56
划分问题是指,有一个集合,判断是否可以把这个结合划分为总和相等的两个集合。
例如:
arr[] = {1, 5, 11, 5}
Output: true
这个数组可以划分为: {1, 5, 5} 和 {11}
arr[] = {1, 5, 3}
Output: false
无法划分为总和相等的两部分
如果划分后的两个集合总和相等,则原集合的总和肯定为偶数,假设为总和为sum。问题即为是否有子集合的总和为sum/2.
递归解决
设函数 isSubsetSum(arr, n, sum/2) 返回true如果存在arr的一个子集合的总和为 sum/2,isSubsetSum函数为分为下面两个子问题
1) 不考虑最后一个元素。问题递归到 isSubsetSum(arr, n-1. sum/2)
2) 考虑最后一个元素。问题递归到 isSubsetSum(arr, n-1. sum/2-arr[n])
上面两种情况有一个返回TRUE即可
isSubsetSum (arr, n, sum/2) = isSubsetSum (arr, n-1, sum/2) ||
例如:
arr[] = {1, 5, 11, 5}
Output: true
这个数组可以划分为: {1, 5, 5} 和 {11}
arr[] = {1, 5, 3}
Output: false
无法划分为总和相等的两部分
如果划分后的两个集合总和相等,则原集合的总和肯定为偶数,假设为总和为sum。问题即为是否有子集合的总和为sum/2.
递归解决
设函数 isSubsetSum(arr, n, sum/2) 返回true如果存在arr的一个子集合的总和为 sum/2,isSubsetSum函数为分为下面两个子问题
1) 不考虑最后一个元素。问题递归到 isSubsetSum(arr, n-1. sum/2)
2) 考虑最后一个元素。问题递归到 isSubsetSum(arr, n-1. sum/2-arr[n])
上面两种情况有一个返回TRUE即可
isSubsetSum (arr, n, sum/2) = isSubsetSum (arr, n-1, sum/2) ||
isSubsetSum (arr, n-1, sum/2 – arr[n-1])
具体实例及实现代码如下所示:
/** * @Title: Partition.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-12 上午9:12:18 * @version V1.0 */package dynamicprogramming;/** * @ClassName: Partition * @Description: 划分问题 * @date 2017-6-12 上午9:12:18 * */public class Partition { /** * * @Title: isSubsetSum * @Description: 判断数组是否可划分 * @param arr 数组 * @param n 数组长度 * @param sum 数组和 * @return * @return boolean * @throws */ public static boolean isSubsetSum(int[] arr, int n, int sum){ //边界条件判断 if(sum == 0) return true; if( n == 0 && sum!= 0) return false; //如果最后一个元素比sum大,就不考虑该元素 if(arr[n-1] > sum) return isSubsetSum(arr, n-1, sum); //分别判断包括最后一个元素和不包括最后一个元素 return isSubsetSum(arr, n-1, sum) || isSubsetSum(arr, n-1, sum - arr[n-1]); } /** * * @Title: findPartitionRecursion * @Description: 利用递归求解数组划分问题 * @param arr 数组名 * @param n 数组长度 * @return * @return boolean * @throws */ public static boolean findPartitionRecursion(int[] arr, int n){ int sum = 0; for(int i = 0; i < n; i++){ sum += arr[i]; } //sum为奇数 if(sum%2 != 0) return false; return isSubsetSum(arr, n, sum/2); } //时间复杂度:最快情况为 O(2^n),即每个元素有选或不选的两种选择 public static boolean findPartition(int[] arr, int n){ int sum = 0; for(int i = 0; i < n; i++){ sum += arr[i]; } if(sum %2 != 0) return false; //创建状态转移矩阵 boolean[][] tc = new boolean[sum/2 + 1][n+1]; //初始化状态转移矩阵 for(int i = 0; i <= n; i++){ tc[0][i] = true; } for(int i = 1; i <= sum/2; i++){ tc[i][0] = false; } //构建状态转移矩阵 for(int i = 1; i <= sum/2; i++){ for(int j = 1; j <=n; j++){ tc[i][j] = tc[i][j-1]; if(i >= arr[j-1]) tc[i][j] = tc[i][j] || tc[i-arr[j-1]][j-1]; } } //打印状态转移矩阵 for(int i = 0; i < sum/2; i++){ for(int j = 0; j <= n; j++){ System.out.print(tc[i][j] + " "); } System.out.println(); } return tc[sum/2][n]; } /** * @Title: main * @Description: 测试用例 * @param args * @return void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub int[] arr = {3, 1, 5, 9, 10}; int n = arr.length; if(findPartitionRecursion(arr, n) == true) System.out.println("数组能够被划分"); else System.out.println("数组不能被划分"); if(findPartition(arr, n) == true) System.out.println("dp数组能够被划分"); else System.out.println("dp数组不能被划分"); }}//时间复杂度为 O(sum*n)
阅读全文
0 0
- 动态规划实例(十四):划分问题
- 整数划分系列问题(动态规划)
- 动态规划-整数划分问题(2)
- 整数划分问题(动态规划)
- 整数划分问题(动态规划)
- 集合的划分问题(动态规划DP)
- 整数划分问题(动态规划||母函数)HIT 1402
- 整数划分(动态规划)
- 整数划分问题解法2-动态规划
- 整数划分问题解法2-动态规划
- 整数划分问题---动态规划、递归
- 整数划分问题---动态规划、递归
- 经典问题 整数划分(动态规划)
- 整数划分问题——动态规划
- 动态规划解决整数划分的问题
- 整数划分问题的动态规划算法
- 动态规划问题实例讲解
- 划分数(动态规划(DP))
- caffe中 insert_splits Unknown bottom blob
- 细数linux内核里那些偏门的C语言语法(一)简化三目运算
- QT 打开文件对话框
- 解决“Maven项目中的Dynamic Web Module 3.0 requires Java 1.6 or newer”问题
- 对于org.apache.commons.dbcp.BasicDataSource的配置认知
- 动态规划实例(十四):划分问题
- Unity3D之第一人称第三人称角色控制组件修改C#版本
- Spring NamedParameterJdbcTemplate
- Hadoop搭建并执行MapReduce
- java回忆篇
- Generative Adversarial Nets (GAN)解读
- maven项目,本项目中增加jar包并引用
- unity3d实现视频播放
- BZOJ 4080 [Wf2014]Sensor Network 随机化