Si le nombre de nombres doit être très simple, s'il y en a deux, la moitié d'entre eux peut être énumérée. Pour plus d'un, vous pouvez vous référer à l'algorithme ci-dessous et le modifier à une longueur fixe
.
Si le nombre de nombres n'est pas certain, 0 ne peut pas exister merci de vous y référer
;
Traversez la récursion en fonction de la longueur de la formule, car elle peut être élaguée et l'efficacité est considérable
function count (num) {
if (!(num > 1)) { return [] }
var equations = []
var eq = []
for (let len = 2; len <= num; len += 1) {
_countByLen(num, eq, 0, len, 0)
}
return equations
function _countByLen (num, eq, i, len, sum) {
if (i === len) {
if (sum === num) {
equations.push(eq.join('+'))
}
return
}
for (let n = eq[i - 1] || 1; n < num; n += 1) {
let newSum = n + sum
if (newSum > num) { break }
eq[i] = n
_countByLen(num, eq, i + 1, len, newSum)
}
}
}
count(5) // ['1+4', '2+3', '1+1+3', '1+2+2', '1+1+1+2', '1+1+1+1+1']
La façon dont j'y pensais au début était de mettre en cache 1~n résultats de formule à chaque fois de manière récursive. L'enregistrer est une perte d'espace, et les parcours répétés sont également très lents
.
function count (num) {
if (!(num > 1)) { return [] }
var equations = [,[[1]]]
_count(num)
return equations[num].slice(0, -1).map(eq => eq.join('+'))
function _count (num) {
if (equations[num]) { return equations[num] }
let halfNum = Math.floor(num / 2)
let eqNum = [] // 即 equations[num]
for (let n = 1; n <= halfNum; n += 1) {
_count(num - n).forEach(eq => {
if (n <= eq[0]) {
eqNum.push([n].concat(eq))
}
})
}
eqNum.push([num])
equations[num] = eqNum
return eqNum
}
}
count(5) // ["1+1+1+1+1", "1+1+1+2", "1+1+3", "1+2+2", "1+4", "2+3"]
Il n’y a pas de solution simplement parce que vous n’avez pas donné suffisamment de conditions, cela peut être fait avec des entiers positifs. Avec la récursion la plus simple, la complexité temporelle est inacceptable. Le programme avec n=100 plantera immédiatement La programmation dynamique que j'utilise utilise une matrice pour enregistrer s[i,j] pour enregistrer les résultats correspondants, de sorte qu'il n'est pas nécessaire de recalculer les résultats précédents à chaque fois. Parmi eux, si, j, i=n, le nombre de combinaisons commençant par j, car il n'y a pas de cas de 0, donc c'est s[i,0]. Ce que je mets c'est s[i,1]. +s[i,2]+. Le résultat de ..+s[i,j] Par exemple, s[5,1] signifie n=5, 1+1+1+1+1, 1+1+. 1+2, 1+1+1+ 3, 1+1+1+4, 1+2+2, 5 cas, En fait, selon cette méthode, on voit facilement que s[i,1] =s[i-1,0], donc s [i,0]=s[i,1]+s[i,2]+...+s[i,j] s[i,0] =s[i-1,0]+s[i ,2]+...+s[i,j] Parmi eux, si on supprime les conditions répétées, il suffit de calculer s[i,i], s[i,0]=s[i-1,0] +...+s[i,i] Puisque s[i,i]=1, il suffit de calculer s[i,2] +s[i,3]+...+s[i à la fin,i-1] résultat Parce que les combinaisons de nombres suivantes peuvent être assemblées par les combinaisons précédentes, identique à s[i, 1] = s[i-1,0], s[i,j] = s[i-j,k], où j > 1, j <= k <= i Ce qui suit est le pseudo-code
function(s, n) {
s <= {0,0};
for(i = 1 to n)
for (j = 1 to floor(i/2) )
if(j = 1)
s[i][j] = s[i-1][0]
else
temp = 0;
for(k = j to i)
temp += s[i-j][k]
s[i][j] = temp
s[i][0] += s[i][j]
s[i][j] = 1,
s[i][0]++
return s
}
Il semble qu'il puisse être encore optimisé. Lors du calcul de si,j>1, le nombre de combinaisons précédentes peut être enregistré à l'avance et le temps peut être échangé dans l'espace. J'espère que cela vous aidera
Cette chose a une fonction appelée fonction de division P J'ai déjà posé une petite question d'algorithme à ce sujet : les 9 milliards de noms de Dieu Cependant, ma question ne nécessite que le nombre de divisions entières et n'implique pas de combinaisons spécifiques, c'est probablement impliqué dans l'article ci-dessus 拆分函数P
Il est préférable que ce type de logique algorithmique ait certaines restrictions. Je pense provisoirement qu'il existe un nombre spécifié de numéros d'éléments et de numéros cibles.
Version Java :
import java.util.ArrayList;
import java.util.Arrays;
class SumSet {
static void sum_up_recursive(ArrayList<Integer> numbers, int target, ArrayList<Integer> partial) {
int s = 0;
for (int x: partial) s += x;
if (s == target)
System.out.println("sum("+Arrays.toString(partial.toArray())+")="+target);
if (s >= target)
return;
for(int i=0;i<numbers.size();i++) {
ArrayList<Integer> remaining = new ArrayList<Integer>();
int n = numbers.get(i);
for (int j=i+1; j<numbers.size();j++) remaining.add(numbers.get(j));
ArrayList<Integer> partial_rec = new ArrayList<Integer>(partial);
partial_rec.add(n);
sum_up_recursive(remaining,target,partial_rec);
}
}
static void sum_up(ArrayList<Integer> numbers, int target) {
sum_up_recursive(numbers,target,new ArrayList<Integer>());
}
public static void main(String args[]) {
Integer[] numbers = {3,9,8,4,5,7,10};
int target = 15;
sum_up(new ArrayList<Integer>(Arrays.asList(numbers)),target);
}
}
Version C# :
public static void Main(string[] args)
{
List<int> numbers = new List<int>() { 3, 9, 8, 4, 5, 7, 10 };
int target = 15;
sum_up(numbers, target);
}
private static void sum_up(List<int> numbers, int target)
{
sum_up_recursive(numbers, target, new List<int>());
}
private static void sum_up_recursive(List<int> numbers, int target, List<int> partial)
{
int s = 0;
foreach (int x in partial) s += x;
if (s == target)
Console.WriteLine("sum(" + string.Join(",", partial.ToArray()) + ")=" + target);
if (s >= target)
return;
for (int i = 0; i < numbers.Count; i++)
{
List<int> remaining = new List<int>();
int n = numbers[i];
for (int j = i + 1; j < numbers.Count; j++) remaining.Add(numbers[j]);
List<int> partial_rec = new List<int>(partial);
partial_rec.Add(n);
sum_up_recursive(remaining, target, partial_rec);
}
}
Version Rubis :
def subset_sum(numbers, target, partial=[])
s = partial.inject 0, :+
# check if the partial sum is equals to target
puts "sum(#{partial})=#{target}" if s == target
return if s >= target
(0..(numbers.length - 1)).each do |i|
n = numbers[i]
remaining = numbers.drop(i+1)
subset_sum(remaining, target, partial + [n])
end
end
subset_sum([3,9,8,4,5,7,10],15)
Version Python :
def subset_sum(numbers, target, partial=[]):
s = sum(partial)
# check if the partial sum is equals to target
if s == target:
print "sum(%s)=%s" % (partial, target)
if s >= target:
return
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i+1:]
subset_sum(remaining, target, partial + [n])
if __name__ == "__main__":
subset_sum([3,9,8,4,5,7,10],15)
#输出:
#sum([3, 8, 4])=15
#sum([3, 5, 7])=15
#sum([8, 7])=15
#sum([5, 10])=15
Si la condition donnée est un nombre positif, changez le tableau en 1~N. La même logique s'applique aux nombres négatifs.
Cet algorithme est relativement simple Si le nombre à décomposer est un nombre pair tel que 18, alors presque le résultat sera (18/2+1) combinaisons. Ensuite, le premier nombre augmente à partir de 0 et le deuxième nombre commence à partir de. le maximum Diminuez simplement la valeur S'il s'agit d'un nombre impair 17, alors vous pouvez y ajouter 1 puis le diviser par 2, et il devient à nouveau (18/2). Ensuite, le premier nombre commence à augmenter à partir de 0, et. le deuxième nombre diminue par rapport à la valeur maximale. C'est tout
Les vrais chiffres n'ont pas de solution
Les nombres négatifs n'ont pas de solution
Si le nombre de nombres doit être très simple, s'il y en a deux, la moitié d'entre eux peut être énumérée. Pour plus d'un, vous pouvez vous référer à l'algorithme ci-dessous et le modifier à une longueur fixe
Si le nombre de nombres n'est pas certain, 0 ne peut pas exister merci de vous y référer
Traversez la récursion en fonction de la longueur de la formule, car elle peut être élaguée et l'efficacité est considérable
La façon dont j'y pensais au début était de mettre en cache 1~n résultats de formule à chaque fois de manière récursive. L'enregistrer est une perte d'espace, et les parcours répétés sont également très lents
.Si c'est un nombre réel... cette question n'a aucun sens
Écrivez un ajout deux par deux
Écrivez une récursivité ici... Je ne connais que peu la récursivité. .
R
S
Il n’y a pas de solution simplement parce que vous n’avez pas donné suffisamment de conditions, cela peut être fait avec des entiers positifs. Avec la récursion la plus simple, la complexité temporelle est inacceptable. Le programme avec n=100 plantera immédiatement
La programmation dynamique que j'utilise utilise une matrice pour enregistrer s[i,j] pour enregistrer les résultats correspondants, de sorte qu'il n'est pas nécessaire de recalculer les résultats précédents à chaque fois.
Parmi eux, si, j, i=n, le nombre de combinaisons commençant par j, car il n'y a pas de cas de 0, donc c'est s[i,0]. Ce que je mets c'est s[i,1]. +s[i,2]+. Le résultat de ..+s[i,j]
Par exemple, s[5,1] signifie n=5, 1+1+1+1+1, 1+1+. 1+2, 1+1+1+ 3, 1+1+1+4, 1+2+2, 5 cas,
En fait, selon cette méthode, on voit facilement que s[i,1] =s[i-1,0], donc
s [i,0]=s[i,1]+s[i,2]+...+s[i,j]
s[i,0] =s[i-1,0]+s[i ,2]+...+s[i,j]
Parmi eux, si on supprime les conditions répétées, il suffit de calculer s[i,i],
s[i,0]=s[i-1,0] +...+s[i,i]
Puisque s[i,i]=1, il suffit de calculer
s[i,2] +s[i,3]+...+s[i à la fin,i-1] résultat
Parce que les combinaisons de nombres suivantes peuvent être assemblées par les combinaisons précédentes,
identique à s[i, 1] = s[i-1,0],
s[i,j] = s[i-j,k], où j > 1, j <= k <= i
Ce qui suit est le pseudo-code
Ce qui suit est implémenté en PHP
Il semble qu'il puisse être encore optimisé. Lors du calcul de si,j>1, le nombre de combinaisons précédentes peut être enregistré à l'avance et le temps peut être échangé dans l'espace.
J'espère que cela vous aidera
Cette chose a une fonction appelée fonction de division P
J'ai déjà posé une petite question d'algorithme à ce sujet : les 9 milliards de noms de Dieu
Cependant, ma question ne nécessite que le nombre de divisions entières et n'implique pas de combinaisons spécifiques, c'est probablement impliqué dans l'article ci-dessus
拆分函数P
Il est préférable que ce type de logique algorithmique ait certaines restrictions. Je pense provisoirement qu'il existe un nombre spécifié de numéros d'éléments et de numéros cibles.
Version Java :
Version C# :
Version Rubis :
Version Python :
Si la condition donnée est un nombre positif, changez le tableau en 1~N. La même logique s'applique aux nombres négatifs.
Cet algorithme est relativement simple
.Si le nombre à décomposer est un nombre pair tel que 18, alors presque le résultat sera (18/2+1) combinaisons. Ensuite, le premier nombre augmente à partir de 0 et le deuxième nombre commence à partir de. le maximum Diminuez simplement la valeur
S'il s'agit d'un nombre impair 17, alors vous pouvez y ajouter 1 puis le diviser par 2, et il devient à nouveau (18/2). Ensuite, le premier nombre commence à augmenter à partir de 0, et. le deuxième nombre diminue par rapport à la valeur maximale. C'est tout