Algorithm 子集和算法
我正在研究这个问题: 子集和问题以一组Algorithm 子集和算法,algorithm,dynamic-programming,subset-sum,Algorithm,Dynamic Programming,Subset Sum,我正在研究这个问题: 子集和问题以一组X={x1,x2,…,xn}整数和另一个K整数作为输入。问题是检查是否存在X的子集X',其元素总和为K,如果存在,则查找子集。例如,如果X={5,3,11,8,2}和K=16那么答案是YES,因为子集X'={5,11}的和为16。实现运行时间至少为O(nK)的子集和算法 注意复杂性O(nK)。我认为动态规划可能会有所帮助 我发现了一个指数时间算法,但它没有帮助 有人能帮我解决这个问题吗?在一般情况下,对于运行时间小于O(2^(n/2))的子集和,没有已知的算
X={x1,x2,…,xn}
整数和另一个K
整数作为输入。问题是检查是否存在X
的子集X'
,其元素总和为K
,如果存在,则查找子集。例如,如果X={5,3,11,8,2}
和K=16
那么答案是YES
,因为子集X'={5,11}
的和为16
。实现运行时间至少为O(nK)
的子集和算法
注意复杂性O(nK)
。我认为动态规划可能会有所帮助
我发现了一个指数时间算法,但它没有帮助
有人能帮我解决这个问题吗?在一般情况下,对于运行时间小于O(2^(n/2))的子集和,没有已知的算法。因为看起来所有的数字都是正数,所以可以使用动态规划来解决这个问题: 启动一个大小为K+1的布尔数组
可能
,第一个值为true,其余值为false。第i个值将表示是否可以实现i的子集和。对于集合中的每个数字n,循环遍历可能的
数组,如果第i个值为真,则将第i+n个值也设置为真
最后,如果可能
中的第k个值为真,则可以形成k的子集和。问题在O(NK)时间内解决
对应用于不保证为正的整数集的该算法进行了详细解释。我建议阅读的算法。算法存在于那里,请参见伪多项式时间动态规划解对于O(P*n)
解,解不是多项式时间,是(P,n)中的多项式,但它不是n+log P(输入大小)中的多项式,因为P
可以非常大,如2^n,解P*n=(2^n)*一般来说,n不是多项式时间解,但当p有某个多项式函数的界时,n是多项式时间算法
这个问题是NPC,但它有一个伪多项式时间
算法,属于问题,也有问题,这意味着,除非p=NP,否则你找不到任何伪多项式时间
算法,而这个问题不在这一问题范围内,所以从某种程度上说很容易
我说的尽可能简单,但这不是强NP完全或弱NP完全问题的精确定义
有关详细信息,请参见第4章。无效子项(int arr[],int size,int target){
void subsetSum (int arr[], int size, int target) {
int i, j ;
int **table ;
table = (int **) malloc (sizeof(int*) * (size+1)) ;
for ( i = 0 ; i <= size ; i ++ ) {
table[i] = (int *) malloc (sizeof(int) * (target+1)) ;
table[i][0] = 1 ;
}
for ( j = 1 ; j <= target ; j ++ )
table[0][j] = 0 ;
for ( i = 1 ; i <= size ; i ++ ) {
for ( j = 1 ; j <= target ; j ++ )
table[i][j] = table[i-1][j] || (arr[i-1] <= j && table[i-1][j-arr[i-1]] ) ;
}
if ( table[size][target] == 1 )
printf ( "\ntarget sum found\n" ) ;
else printf ( "\nTarget sum do not found!\n" ) ;
free (table) ;
}
int i,j;
int**表格;
表=(int**)malloc(sizeof(int*)*(size+1));
对于(i=0;iDP)一维数组解决方案(这里DP数组处理顺序很重要)
bool subsetsum\u dp(向量和向量,整数和)
{
int n=v.size();
常量int MAX_元素=100;
常量int最大元素值=1000;
静态int-dp[MAX_-ELEMENT*MAX_-ELEMENT_-VALUE+1];memset(dp,0,sizeof(dp));
dp[0]=1;
对于(int i=0;i=0;j--)
{
如果(j-v[i]<0)继续;
如果(dp[j-v[i]])dp[j]=1;
}
}
返回dp[总和]?真:假;
}
设M为所有元素之和。
注意K布尔hasSubset(int arr[],int remSum,int lastElem){
if(remSum==0)返回true;
else if(remSum!=0&&lastelemsum)返回hasSubset(arr、remSum、lastElem-1);
否则返回(hasSubset(arr,remSum,lastElem-1)| | hasSubset(arr,remSum,arr[lastElem],lastElem-1));
}
考虑第i个元素。它将对子集和起作用或不起作用。如果它对和起作用,则“和值”将减少等于第i个元素的值。如果它不起作用,则我们需要搜索“和值”在剩下的元素中。子集和是我在Macalester学习的第一个NP完全问题。这个问题被浏览了36000多次,但我没有看到足够的答案来详细解释算法的逻辑。所以我想我尝试这样做
假设:
为了简单起见,首先我假设输入集X
只包含正整数,并且k
为正。但是,我们可以调整算法来处理负整数,如果k
为负
逻辑:
该算法或任何DP问题的关键在于分解问题,从基本情况开始。
然后我们可以利用我们知道的一些知识在基本情况基础上进行构建:
X
为空,则无法求和k
的任何值X
包含k
,则它有一个子集和k
x1
的子集是X
的子集,那么X
将有一个子集和k1
,即x1
X={x1,x1,x3,…,xn,xn+1}
。我们知道它有一个子集和k1
,如果x1={x1,x1,x3,…,xn}
有一个子集和k-k1
X={4}
的子集和为4,因为它本身就是集合的一部分x1={1,3,5}
,它是集合X={1,3,5,2,8}
的子集。如果x1
的子集和为k1=8
,那意味着X
也有一个子集和为8,因为x1
是X
的子集bool subsetsum_dp(vector<int>& v, int sum)
{
int n = v.size();
const int MAX_ELEMENT = 100;
const int MAX_ELEMENT_VALUE = 1000;
static int dp[MAX_ELEMENT*MAX_ELEMENT_VALUE + 1]; memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 0; i < n; i++)
{
for (int j = MAX_ELEMENT*MAX_ELEMENT_VALUE; j >= 0; j--)
{
if (j - v[i] < 0) continue;
if (dp[j - v[i]]) dp[j] = 1;
}
}
return dp[sum] ? true : false;
}
let m be a Boolean array [0...M]
set all elements of m to be False
m[0]=1
for all numbers in the set let a[i] be the ith number
for j = M to a[i]
m[j] = m[j] | m[j-a[i]];
boolean hasSubset(int arr[],int remSum,int lastElem){
if(remSum==0) return true;
else if(remSum!=0 && lastElem<0) return false;
if(arr[lastElem]>remSum) return hasSubset(arr, remSum, lastElem-1);
else return (hasSubset(arr, remSum, lastElem-1) ||hasSubset(arr, remSum-arr[lastElem], lastElem-1));
}
X = {1,3,5,2,8}
k = 9
0 1 2 3 4 5 6 7 8 9
_ _ _ _ _ _ _ _ _ _
0| F F F F F F F F F F
1|
2|
3|
4|
5|
0 1 2 3 4 5 6 7 8 9
_ _ _ _ _ _ _ _ _ _
0| F F F F F F F F F F
1| F T F F F F F F F F
2| F T F T T F F F F F
3| F T F T T T T F T T
4| F T T T T T T T T T
5| F T T T T T T T T T
import java.util.*;
public class SubSetSum {
public static boolean subSetSum(int[] a, int k){
if(a == null){
return false;
}
//n items in the list
int n = a.length;
//create matrix m
boolean[][] m = new boolean[n + 1][k + 1]; //n + 1 to include 0, k + 1 to include 0
//set first row of matrix to false. This also prevent array index out of bounds: -1
for(int s = 0; s <= k; s++){
m[0][s] = false;
}
//populate matrix m
for(int i = 1; i <= n; i++){
for(int s = 0; s <= k; s++){
if(s - a[i-1] >= 0){ //when it goes left we don't want it to go out of bounds. (logic 4)
m[i][s] = (m[i-1][s] || a[i-1] == s || m[i-1][s - a[i-1]]);
} else {
m[i][s] = (m[i-1][s] || a[i-1] == s);
}
}
}
//print matrix
print(m);
return m[n][k];
}
private static void print(boolean[][] m){
for(int i = 0; i < m.length; i++){
for(int j = 0; j < m[i].length; j++){
if(m[i][j]){
System.out.print("T");
} else {
System.out.print("F");
}
}
System.out.print("\n");
}
}
public static void main(String[] args){
int[] array = {1,3,5,2,8};
int k = 9;
System.out.println(subSetSum(array,k));
}
}
┌─────────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ (index) │ 0 │ 2 │ 3 │ 5 │ 7 │ 8 │ 10 │ 11 │ 13 │ 14 │ 15 │ 16 │
├─────────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
│ 0 │ true │ │ │ │ │ │ │ │ │ │ │ │
│ 5 │ true │ │ │ true │ │ │ │ │ │ │ │ │
│ 3 │ true │ │ true │ true │ │ true │ │ │ │ │ │ │
│ 11 │ true │ │ true │ true │ │ true │ │ true │ │ true │ │ true │
│ 8 │ true │ │ true │ true │ │ true │ │ true │ true │ true │ │ true │
│ 2 │ true │ true │ true │ true │ true │ true │ true │ true │ true │ true │ true │ true │
└─────────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
public class SubSetSum {
boolean[][] solution;
int[] input;
int k;
public SubSetSum(int[] input, int targetSum) {
this.input = input;
this.k = targetSum;
this.solution = new boolean[input.length+1][k+1];
}
public boolean subsetSum() {
int n = input.length;
for (int i = 0; i <= n; i++) { //case 1
solution[i][0] = true;
}
for (int j = 0; j <= k; j++) { // case 2
solution[0][j] = false;
}
for (int i = 1; i <= n; i++) { // n times
for (int j = 1; j <= k; j++) { // k times and time complexity O(n*k)
if(solution[i-1][j]) {
solution[i][j] = solution[i-1][j]; // case 3
continue;
}
if(j >= input[i-1]) { // case 4
solution[i][j] = solution[i-1][j-input[i-1]];
}
}
}
return solution[n][k];
}
}
function subsetsum(a, n) {
var r = [];
for (var i = parseInt(a.map(function() { return 1 }).join(''), 2); i; i--) {
var b = i.toString(2).split('').reverse().map(function(v, i) {
return Number(v) * a[i]
}).filter(Boolean);
if (eval(b.join('+')) == n) r.push(b);
}
return r;
}
var a = [5, 3, 11, 8, 2];
var n = 16;
console.log(subsetsum(a, n)); // -> [[3, 11, 2], [5, 3, 8], [5, 11]]
public void solveSubsetSum(){
int set[] = {2,6,6,4,5};
int sum = 9;
int n = set.length;
// check for each element if it is a part of subset whose sum is equal to given sum
for (int i=0; i<n;i++){
if (isSubsetSum(set, sum, i, n)){
Log.d("isSubset:", "true") ;
break;
}
else{
Log.d("isSubset:", "false") ;
}
k=0; // to print time complexity pattern
}
}
private boolean isSubsetSum(int[] set, int sum, int i, int n) {
for (int l=0;l<k; l++){
System.out.print("*");
// to print no of time is subset call for each element
}
k++;
System.out.println();
if (sum == 0){
return true;
}
if (i>=n){
return false;
}
if (set[i] <= sum){
// current element is less than required sum then we have to check if rest of the elements make a subset such that its sum is equal to the left sum(sum-current element)
return isSubsetSum(set, sum-set[i], ++i, n);
}
else { //if current element is greater than required sum
return isSubsetSum(set, sum, ++i, n);
}
}