问题一:给一个数组,输出这个数组拆分为两个数组,使得两个数组的差值最小
//注意target就是数组总和的一半:sum/2
//dp[i][j]表示从数组的[0,i]下标范围内选取若干个正整数,达到总和为j的最小总和
public static int func(int[] nums){
int sum = 0;
for(int i:nums) sum+=i;
int target = sum/2;
int[][] dp = new int[nums.length+1][target+1];
for (int i=1;i<=nums.length;i++){
for (int j=1;j<=target;j++){
if (j>=nums[i-1]){//如果大于 就可以进行二选一
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-nums[i-1]]+nums[i-1]);
}else{
dp[i][j] = dp[i-1][j];
}
}
}
return dp[nums.length][target];
}
问题二:给一个数组,是否可以等值分割成两个子集,使得两个子集的元素和相等。
public static boolean func2(int[] nums) {
int n = nums.length;
int sum = 0;
for(int i:nums) sum+=i;
int target = sum/2;
boolean[][] dp = new boolean[n + 1][target + 1];
// 如果不选取任何正整数,则被选取的正整数等于 0。因此对于所有 0≤i<n,都有 dp[i][0]=true
for (int i = 0; i <= n; i++) {
dp[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= target; j++) {
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j] | dp[i - 1][j - nums[i - 1]];
}
}
}
return dp[n][target];
}
问题三:将一个数组拆分为两个数组使得两个数组的差值最小,求出对应的两个数组
package huatielu;/*
@author Oblak
@date 2022/4/14
@description 可以求得:将一个数组拆分为两个数组使得两个数组的差值最小
求出对应的两个数组
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class bag01 {
public static void main(String[] args) {
int[] nums = new int[]{1,3,5,7,5,2,5};
int sum = 0;
HashMap<Integer,Integer> map= new HashMap<>();
for (int i:nums){
sum+=i;
map.put(i,map.getOrDefault(i,0)+1);
}
int ans = func(nums, sum / 2);
boolean[][] booleans = func2(nums, ans);
List<Integer> list = new ArrayList<>();
int target = ans;
//寻找路径 从原来的boolean中先找target位置是否有满足的条件,有的话加入list,然后更新target
int n = nums.length;
while (target>0){
for (int i=1;i<=n;i++){
if (booleans[i][target]){
list.add(nums[i-1]);
//System.out.println(nums[i-1]);
target-=nums[i-1];
n=i-1;//之后的n只能从前面的糖果袋中取
break;
}
}
}
for (int i=0;i<list.size();i++){
if (i==0) System.out.print(list.get(0));
else System.out.print(" "+list.get(i));
map.put(list.get(i),map.get(list.get(i))-1);
}
System.out.println();
List<Integer> list2 = new ArrayList<>();
for (int i=0;i<nums.length;i++){
if (map.get(nums[i])>0){
list2.add(nums[i]);
map.put(nums[i],map.get(nums[i])-1);
}
}
for (int i=0;i<list2.size();i++){
if (i==0) System.out.print(list2.get(0));
else System.out.print(" "+list2.get(i));
}
}
public static int func(int[] nums,int target){
int[][] dp = new int[nums.length+1][target+1];
for (int i=1;i<=nums.length;i++){
for (int j=1;j<=target;j++){
if (j>=nums[i-1]){
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-nums[i-1]]+nums[i-1]);
}else{
dp[i][j] = dp[i-1][j];
}
}
}
for (int i=0;i<dp.length;i++){
System.out.println(Arrays.toString(dp[i]));
}
System.out.println(dp[nums.length][target]);
return dp[nums.length][target];
}
public static boolean[][] func2(int[]nums,int target){
int n = nums.length;
boolean[][] dp = new boolean[n + 1][target + 1];
// 如果不选取任何正整数,则被选取的正整数等于 0。因此对于所有 0≤i<n,都有 dp[i][0]=true
for (int i = 0; i <= n; i++) {
dp[i][0] = true;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= target; j++) {
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j] | dp[i - 1][j - nums[i - 1]];
}
}
}
for (int i=0;i<dp.length;i++){
System.out.println(Arrays.toString(dp[i]));
}
return dp;
}
}