Je travaille sur ce problème:
Le problème Sous-ensemble Somme prend en entrée un ensemble
X = {x1, x2 ,…, xn}
d'entiersn
et un autre entierK
. Le problème est de vérifier s’il existe un sous-ensembleX'
deX
dont la somme des éléments estK
et trouve le sous-ensemble s’il en existe. Par exemple, siX = {5, 3, 11, 8, 2}
etK = 16
, la réponse estYES
puisque le sous-ensembleX' = {5, 11}
a la somme de16
. Implémentez un algorithme pour Subset Sum dont le temps d'exécution est au moinsO(nK)
.
Remarquez la complexité O(nK)
. Je pense que la programmation dynamique peut aider.
J'ai trouvé un algorithme de temps exponentiel, mais ça n'aide pas.
Quelqu'un peut-il m'aider à résoudre ce problème?
Comme il semble que tous vos chiffres sont positifs, vous pouvez résoudre ce problème en utilisant la programmation dynamique:
Start sera un tableau booléen possible
de taille K + 1 avec la première valeur true, le reste faux. La ième valeur déterminera si une somme de i est possible à réaliser. Pour chaque nombre n de votre ensemble, parcourez le tableau possible
. Si la ith valeur est true, définissez également la i + nième valeur sur true.
À la fin, si la kième valeur de possible
est vraie, vous pouvez alors former une somme de k. Problème résolu dans le temps O(NK).
La page de Wikipédia sur le problème de la somme des sous-ensembles contient une explication détaillée de cet algorithme appliquée aux ensembles d'entiers non garantis positifs.
Je suggère de lire l'algorithme de Wiki . L'algorithme existe ici, voir Solution de programmation dynamique du temps pseudo-polynomial pour la solution O(P*n)
, La solution n'est pas du temps polynomial, est polynomiale dans (p, n) mais n'est pas polynomiale dans n + log P (taille de l'entrée ) et parce que P
peut être très grand comme 2 ^ n, la solution P * n = (2 ^ n) * n n’est pas une solution temporelle polynomiale en général, mais lorsque p est lié par une fonction polynomiale de n, l’algorithme polynomial de temps .
Ce problème est NPC, mais il existe un algorithme Pseudo polynomial time
pour celui-ci, et appartient à weakly NP-Complete
problèmes, il y a aussi Strongly NP-Complete
problèmes, ce qui signifie que vous ne pouvez trouver aucun algorithme pseudo polynomial time
pour eux à moins de P = NP , et ce problème ne se trouve pas dans cette gamme de problèmes, donc, en quelque sorte, est facile.
J'ai dit cela aussi simplement que possible, mais ce n'est pas une définition exacte d'un problème Fortement NP-Complet ou Faiblement NP-Complet.
Pour plus de détails, voir Garey et Johnson chapitre 4.
Il semble que je sois en retard à la fête, voici mes deux centimes. Nous allons créer un boolean[] solution[n+1][k+1]
tel que solution[i][j]
est true
si vous utilisez les premiers éléments i
(index 0
à i-1
), nous pouvons obtenir la somme j
de l'ensemble; sinon false
. Nous retournerons solution[k][n]
enfin:
On peut en déduire les points suivants:
Sur la base des points ci-dessus, nous pouvons facilement écrire l'algorithme ci-dessous.
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];
}
}
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) ;
}
Il n'y a pas d'algorithme connu pour la somme de sous-ensembles qui s'exécute dans moins de O (2 ^ (n/2)), dans le cas général.
Solution DP avec un tableau à une dimension (l’ordre de traitement de la matrice DP importe ici).
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;
}
Les réponses ci-dessus sont toutes excellentes, mais ne donnez pas le plus grand aperçu de la manière dont cela pourrait fonctionner pour les nombres positifs et négatifs.
Étant donné un ensemble ordonné d’entiers, définissez deux variables X et Y telles que
X = somme des éléments négatifs
Y = somme des éléments positifs
et opérez sur votre ensemble initial comme si vous récursiez dans un arbre binaire en appliquant ces règles dans cet ordre
Les réponses ci-dessus sont plus détaillées et précises, mais pour une vue très large de la façon dont cela devrait se dérouler, dessinez un arbre binaire. Qu'est-ce que la longueur de ceci suggère sur le runtime?
soit M la somme de tous les éléments. Notez que K <= M
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]];
Puis testez simplement m [k]
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));
}
Considérons le ième élément. Soit il contribuera à la somme du sous-ensemble ou ne le sera pas. si elle contribue pour la somme, la "valeur de la somme" est diminuée de la valeur égale au ième élément. S'il ne contribue pas, nous devons alors rechercher la "valeur de la somme" dans les éléments restants.