4
votes

Comment choisir des éléments de deux tableaux de sorte que leur somme soit minimale?

J'ai deux tableaux de longueur égale remplis d'entiers (qui peuvent être positifs ou négatifs mais jamais 0). À chaque index, je peux choisir l'élément de array1 ou de array2, et la valeur absolue de la somme de ces éléments doit être minimale.

Par exemple:

At index 0 : -3 from a2
At index 1 : 2 from a1
At index 2 : 1 from a1

Le La bonne réponse serait de choisir comme ceci:

a1 = [2, 2, 1]
a2 = [-3, -3, -4]

Ainsi, la somme finale serait 0.


9 commentaires

Quelle est votre approche alors?


Vous pouvez le faire de haut en bas ou de bas en haut.


Mon approche était de prendre l'élément avec la valeur absolue minimale des deux tableaux, ce qui fonctionne dans de nombreux cas mais échoue dans l'exemple que j'ai montré dans la question. Cela peut-il être fait sans dp?


Cela peut-il être fait sans dp ? Probablement (peut-être améliorer l'espace). Cependant, pouvez-vous donner plus d'exemples, puisque valeur absolue de la somme est un peu floue pour moi.


Bien sûr, a1 = [2, 1, 1, -1] a2 = [-1, -2, -2, -4] ans = [-1, 1, 1, -1] Btw, ce que je veux minimiser est pos + abs (nég + pos). Ici, pos et neg sont les sommes des valeurs positives et négatives du tableau final qui sera formé après avoir choisi les éléments idéaux des deux éléments originaux. C'est pourquoi j'ai choisi -3, 2, 1 sur 2, 2, -4.


qu'en est-il de 0 , est-ce que ça compte comme pos ou neg?


cela signifie-t-il que votre sortie correcte doit être 3 pour l'exemple abs (-3 + 2 + 1) + (2 + 1)? Si tel est le cas, veuillez mettre à jour votre déclaration.


@DistinctlyAverage Ce n'est toujours pas clair en voyant vos commentaires. Pourriez-vous ajouter d'autres exemples de a1 et a2 avec leurs solutions?


@xashru, en fait, il existe encore plusieurs solutions, cela peut aussi être (2, -3, 1). Je mettrai à jour les détails.


3 Réponses :


2
votes

Tout d'abord, simplifiez la question:

  • Créez un tableau b , où b [i] = a1 [i] - a2 [i] .
  • sumA1 = somme de chaque élément de a1 .

Alors le problème devient:

Trouvez un sous-tableau à partir de b , marquez comme c , marquez sa somme comme sumC qui devrait être la plus proche de sumA1 < / code>.

Ou, vous pouvez également dire qu'il devrait avoir un minimum de Math.abs (sumC - sumA1) .

BTW, si c est vide, il est également valide, ce qui signifie choisir tous les index de a1 .

Cette question est alors similaire à celle-ci: Étant donné un tableau d'entrée, trouvez tous les sous-tableaux avec la somme K donnée

Ou, reportez-vous à cet article:

Et, pour revenir à la question de OP:

  • Tous les indices sélectionnés dans b sont pour a2 .
  • Tous les indices non sélectionnés dans b sont pour a1 .

1 commentaires

Les commentaires ne sont pas destinés à une discussion approfondie; cette conversation a été déplacé vers le chat .



0
votes
import itertools as iter
a1 = [2, 2, 1]
a2 = [-3, -3, -4]
a = [a1, a2]
p = len(a1)


def obj_func(b):
    arr = [a[i][j] for i, j in zip(b, range(p))]
    return sum([x for x in arr if x > 0]) + abs(sum(arr))


idx_to_pick = min(iter.product(*([[0, 1]]*p)), key=obj_func)

4 commentaires

C'est fondamentalement la force brute, n'est-ce pas? Puisque cela ne me dérange pas de trouver une solution de force brute, pouvez-vous m'aider à étendre cela là où je veux minimiser cette valeur: pos + abs (neg + pos) Ici, pos et neg sont les sommes des valeurs positives et négatives du tableau final qui sera formé après avoir sélectionné les éléments idéaux des deux éléments originaux. C'est pourquoi j'ai choisi -3, 2, 1 sur 2, 2, -4.


Bien sûr, soyez clair, en gros, ce que vous voulez minimiser est sum (toutes les valeurs positives du tableau final) + abs (sum (toutes les valeurs du tableau)) ?


@DistinctlyAverage, qu'en est-il de 0 , est-ce que cela compte comme pos ou neg? Si ni l'un ni l'autre, alors neg + pos n'est pas égal à la somme de tous.


La déclaration @Indominus Problem indique que pourrait être positif ou négatif mais jamais 0



2
votes

Voici une solution de programmation dynamique qui trouve la valeur minimale pour pos + abs (neg + pos) (selon la mise à jour de OP) et imprime une solution candidate. Nous devons enregistrer la somme totale et la somme des entiers positifs comme état dp pour trouver le minimum. Je ne sais pas si nous pouvons le résoudre sans la dimension pos . La complexité temporelle est O (#elements * (somme des valeurs absolues des éléments) ^ 2) . Bien sûr, si les nombres individuels sont très grands, ce n'est pas une solution réalisable. Dans ce cas, l'approche de force brute fonctionnera lorsque le nombre d'éléments est ~20.

a1 = [2, 1, 1, -1] 
a2 = [-1, -2, -2, -4]
memo = {}   # to store dp state
nxt = {}    # for reconstructing path

def foo(a1, a2, index, total, pos):
    if index == len(a1):
        return pos + abs(total)
    if (index, total, pos) in memo:
        return memo[(index, total, pos)]

    # take from first array
    if a1[index] > 0:
        r1 = foo(a1, a2, index+1, total + a1[index], pos+a1[index])
    else:
        r1 = foo(a1, a2, index+1, total + a1[index], pos)

    # take from second array
    if a2[index] > 0:
        r2 = foo(a1, a2, index+1, total + a2[index], pos+a2[index])
    else:
        r2 = foo(a1, a2, index+1, total + a2[index], pos)

    # save path taken at this step
    if r1 < r2:
        nxt[index] = 0
    else:
        nxt[index] = 1

    memo[index, total, pos] = min(r1, r2)
    return min(r1, r2)

print('minimum sum:', foo(a1, a2, 0, 0, 0))   # minimum sum: 2
# path reconstruction
path = []
node = 0
while node < len(a1):
    path.append(nxt[node])
    node += 1
print('path:', path)   # path: [1, 0, 0, 0]


1 commentaires

C'est nettement plus efficace. Merci pour cela!