Java 动态规划:带负数的完全和
给定一个整数数组和一个和,任务是打印给定数组中和等于给定和的所有子集Java 动态规划:带负数的完全和,java,data-structures,dynamic-programming,subset-sum,Java,Data Structures,Dynamic Programming,Subset Sum,给定一个整数数组和一个和,任务是打印给定数组中和等于给定和的所有子集 Example: Input : arr[] = {1, 2, 3, 4, 5} sum = 10 Output : [4 3 2 1] [5 3 2] [5 4 1] Input : arr[] = {-1, 2, 3, 4, 5} sum = 10 Output : [5 3 2] [5 4 2 -1] 我已经在伪多项式时间
Example:
Input : arr[] = {1, 2, 3, 4, 5}
sum = 10
Output : [4 3 2 1]
[5 3 2]
[5 4 1]
Input : arr[] = {-1, 2, 3, 4, 5}
sum = 10
Output : [5 3 2]
[5 4 2 -1]
我已经在伪多项式时间内使用动态规划实现了这一点。这是子集和问题的一个扩展,它只考虑是否存在这样的子集。我下面的解决方案适用于子集和问题的正数和负数。但是,如果数组包含负数,则无法正确打印子集。该程序正在运行-
import java.util.ArrayList;
// sum problem
class GFG {
static boolean subset[][];
// Returns true if there is a subset of
// set[] with sun equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum) {
// The value of subset[i][j] will be
// true if there is a subset of
// set[0..j-1] with sum equal to i
subset = new boolean[n + 1][sum + 1];
// Fill the subset table in botton
// up manner
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
if (j == 0) {
subset[i][j] = true;
} else if (i <= 0 && sum >= 1)
subset[i][j] = false;
else if (set[i - 1] > j)
subset[i][j] = subset[i - 1][j];
else {
if (set[i - 1] >= 0)
subset[i][j] = subset[i - 1][j] || subset[i - 1][j - set[i - 1]];
else
subset[i][j] = subset[i - 1][j] || subset[i - 1][j + set[i - 1]];
}
}
}
// uncomment this code to print table
// for (int i = 0; i <= sum; i++)
// {
// for (int j = 0; j <= n; j++)
// System.out.println (subset[i][j]);
// }
return subset[n][sum];
}
/* Driver program to test above function */
public static void main(String args[]) {
int set[] = {1, 2, 3, 4, 5};
int sum = 10;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
System.out.println("Done");
ArrayList<Integer> list = new ArrayList<>();
printSubsets(set, n, sum, list);
System.out.println("Finished");
}
static void display(ArrayList<Integer> v) {
System.out.println(v);
}
private static void printSubsets(int[] set, int i, int sum, ArrayList<Integer> list) {
if (i == 0 && sum != 0 && subset[0][sum]) {
list.add(set[i]);
display(list);
list.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0) {
display(list);
list.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (subset[i - 1][sum]) {
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(list);
printSubsets(set, i - 1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= set[i - 1] && subset[i - 1][sum - set[i - 1]]) {
list.add(set[i - 1]);
printSubsets(set, i - 1, sum - set[i - 1], list);
}
}
}
import java.util.ArrayList;
//求和问题
GFG类{
静态布尔子集[];
//如果存在一个子集,则返回true
//设置[],太阳等于给定的和
静态布尔isSubsetSum(整数集[],
整数n,整数和){
//子集[i][j]的值将为
//如果存在一个子集,则为true
//集合[0..j-1]的和等于i
子集=新布尔[n+1][sum+1];
//填写botton中的子集表
//盛气凌人
对于(int i=0;i=0)
子集[i][j]=子集[i-1][j]| |子集[i-1][j-集[i-1];
其他的
子集[i][j]=子集[i-1][j]| |子集[i-1][j+集[i-1];
}
}
}
//取消注释此代码以打印表
//对于(int i=0;i由于您必须打印(或生成)给定集合的所有可能子集(包含正整数和负整数),其总和等于总和,因此您可以执行以下操作:
尝试将集合的每个位置表示为0和1的二进制表示,其中1表示采用该位置的元素,0表示不考虑该位置的元素
求所有位置的总和,其中有1。如果这些值的总和正好等于给定的总和,则打印该子集
所以,总的时间复杂度是O(2^n)
,其中n
是给定集合的长度
您可以查看以下实现
import java.util.Arrays;
public class PerfectSum {
public static void printSubsets(int[] set, int n, int sum) {
int totalSubSets = (1 << n);
for (int i = 1; i < totalSubSets; ++i) { // loop over all possible subsets
int curSum = 0;
for (int j = n - 1; j >= 0; --j) {
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
curSum +=set[j];
}
}
if (curSum == sum) { // valid subset found, then print it
for (int j = n - 1; j >= 0; --j) { // looping in reverse order to print set in decreasing order
if (((i >> j) & 1) > 0) { // if bit at jth position is 1 take that value
System.out.print(set[j] + " ");
}
}
System.out.println("");
}
}
}
public static void main(String[] args) {
int set[] = {-1, 2, 3, 4, 5};
Arrays.sort(set); // To print in non increasing order
int sum = 10;
int n = set.length;
printSubsets(set, n, sum);
}
}
导入java.util.array;
公共类PerfectSum{
公共静态void打印子集(int[]集,int n,int和){
int totalSubSets=(1=0;--j){
若((i>>j)&1)>0{//若第j个位置的位为1,则取该值
curSum+=集合[j];
}
}
如果(curSum==sum){//找到有效子集,则打印它
对于(int j=n-1;j>=0;--j){//按相反顺序循环以降序打印集
若((i>>j)&1)>0{//若第j个位置的位为1,则取该值
系统输出打印(设置[j]+“”);
}
}
System.out.println(“”);
}
}
}
公共静态void main(字符串[]args){
int set[]={-1,2,3,4,5};
Arrays.sort(set);//以非递增顺序打印
整数和=10;
int n=设置长度;
打印子集(集合,n,和);
}
}
您可以将数组的最小负数减去整个集合,使数组中的数字为正数。然后应用动态规划。您的解决方案假设所有值都为正数,因此动态编程数组子集
中填充的j
值为正数,但您不需要o现在考虑负和
您需要做的是更改j
的循环限制,以将动态编程数组填充到
for(int j=negative_sum;j)谢谢你的解决方案。但我认为这是一种蛮力,我们迭代所有的子集以得到合适的子集。有没有什么方法可以用动态规划(即伪多项式时间)来实现呢?因为我们必须打印出所有可能的子集,我们不能在不到O(2^n)的时间内完成它谢谢