Algorithmus split ein array in P subarrays der Summe ausgeglichen
Ich habe ein großes array der Länge N, sagen wir so etwas wie:
2 4 6 7 6 3 3 3 4 3 4 4 4 3 3 1
Muss ich split das array in P subarrays (in diesem Beispiel P=4
sinnvoll wäre), so dass die Summe der Elemente in jedem subarray ist so nah wie möglich an sigma, Wesen:
sigma=(sum of all elements in original array)/P
In diesem Beispiel sigma=15
.
Gründen der übersichtlichkeit, ein mögliches Ergebnis wäre:
2 4 6 7 6 3 3 3 4 3 4 4 4 3 3 1
(sums: 12,19,14,15)
Ich geschrieben habe, eine sehr naive Algorithmus basiert, wie würde ich die Divisionen von hand, aber ich weiß nicht, wie die Verhängung der Bedingung, dass eine division, deren Summen (14,14,14,14,19) ist schlechter als eine, die (15,14,16,14,16).
Vielen Dank im Voraus.
- Warum ist das eine Folge schlechter als die andere? Wenn Sie klären können, dass in Ihrem Kopf, Sie können schreiben Sie es in code. Es ist einfach, dass Sie wollen, zu minimieren, die Summe der Unterschiede (von der idealen Ergebnis, 15)? Es gibt viele Ansätze zu diesem. Zum Beispiel ist die Summe der Unterschiede (wie oben erwähnt), die Summe der Quadrate der Differenzen (die stärker benachteiligt Antworten weiter vom ideal), oder sogar so etwas wie die Standardabweichung.
- Möchten Sie vielleicht haben die sum-of-squared-error als eine gute Maßnahme: Sie Quadrat der Differenz der jede Summe mit sigma und zusammenfassen.
(14,14,14,14,19)
wäre eine Schlechtigkeit von 20, während(15,14,16,14,16)
wäre eine Schlechtigkeit der 4. Natürlich, Sie können spielen, mit den Exponenten. - Ja, du hast Recht, sorry für die nicht mehr klar und vielen Dank für Ihre prompte Antwort. Ich denke, minimieren entweder die Summe der Unterschiede der Quadrate der Unterschiede funktionieren würde. Gibt es irgendeine bekannte Art und Weise, es zu tun "on the fly"? Die eigentliche array-ich habe enthält etwa eine halbe million zahlen, so dass ich glaube nicht, dass unter Berücksichtigung aller möglichen Kombinationen der ersten und dann die Auswahl der am besten balanced ist eine option.
- Passieren, fürchte ich. Das ist eine ganz andere Frage! (Und, als solche, vielleicht besser gefragt als eine separate Frage.) Ich bin mir nicht bewusst, eine einfache Möglichkeit dies zu tun, ohne eine Art "brute-force" - die Sie wahrscheinlich wollen parallelised.
- Das klingt verdächtig ähnlich der 0-1 knapsack problem, würde ich anfangen zu suchen, um es. Aber, dass man keine effiziente Lösung bekannt, so dass ich befürchte, das man nicht entweder. Vielleicht verschieben cs.stackexchange.com?
- Was meinst du mit subarray. Ein konsekutiver subarray oder ist es mehr wie eine Teilfolge?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Lassen Sie uns zuerst formalisieren Ihre Optimierungsproblem durch Angabe der Eingabe -, Ausgabe -, und der Maßstab für jedes mögliche Lösung (ich hoffe das ist in deinem Interesse):
Den Eingang und Ausgabe definieren Sie die Menge der gültigen Lösungen. Die Messen definiert ein Maß für den Vergleich mehrerer Lösungen. Und da sind wir auf der Suche nach einer Lösung mit dem geringsten Unterschied zu der perfekten Lösung (minimierungsproblem), Messen sollte auch minimal sein.
Mit diesen Informationen ist es Recht einfach zu implementieren, die
measure
Funktion (hier in Python):Nun das finden einer optimalen Lösung ist ein wenig härter.
Können wir die Backtracking-Algorithmus für die Suche nach gültigen Lösungen und nutzen Sie die Messen Funktion zu bewerten. Wir haben im Grunde versuchen alle möglichen Kombinationen von P nicht-negative ganze zahlen, die Summe bis zu der Länge(Eine) sind, um alle möglichen gültigen Lösungen. Dies stellt zwar sicher, nicht zu verpassen eine gültige Lösung, es ist im Grunde ein brute-force-Ansatz mit dem Vorteil, dass wir die weglassen können, einige Zweige, die kann nicht besser sein als unsere noch die beste Lösung. E. g. in dem obigen Beispiel, würden wir nicht testen müssen, die Lösungen mit [9,...] (Messen > 38), wenn wir schon eine Lösung mit Messen ≤ 38.
Folgenden pseudocode-Muster von Wikipedia, unser
bt
Funktion sieht wie folgt aus:Den globalen Variablen
P
,optimum
, undoptimum_diff
stellen die problem-Instanz hält die Werte für Eine, P, und sigma, sowie die optimale Lösung und Maß:Nächstes legen wir die
reject
undaccept
Funktionen, die sind ziemlich geradlinig:Diese einfach ablehnt, ein Kandidat, dessen Maß ist schon mehr als unsere noch die optimale Lösung. Und wir akzeptieren jede gültige Lösung.
Den
measure
Funktion ist auch leicht verändert, aufgrund der Tatsache, dassc
enthalten nunNone
Werte:Den verbleibenden zwei Funktion
first
undnext
sind ein wenig komplizierter:Grundsätzlich
first
entweder ersetzt die nächsteNone
Wert in der Liste, die entweder mit0
wenn es nicht der Letzte Wert in der Liste oder der restliche stellen eine gültige Lösung (wenig Optimierung hier), wenn es den letzten Wert in der Liste, oder es zurückNone
wenn es keineNone
Wert in der Liste.next
einfach Schritten die Rechte integer, die von einem oder zurückNone
wenn eine Erhöhung würde einen Verstoß gegen das Gesamt-limit.Nun alles, was Sie brauchen, ist zum erstellen einer problem-Instanz initialisiert die globalen Variablen und rufen
bt
mit der Wurzel:Wenn ich mich nicht Irre hier, eine weitere Ansatz ist die dynamische Programmierung.
Können Sie definieren P[ pos, n ] als die kleinste mögliche "Strafe", die bis zu position pos wenn n subarrays erstellt wurden. Offensichtlich gibt es einige position', so dass
P[pos', n-1] + Strafe(pos", pos) = P[pos, n]
Können Sie einfach minimieren über pos' = 1..pos.
Die naive Implementierung läuft in O(N^2 * M), wobei N die Größe des ursprünglichen Arrays und M - Anzahl der Unterteilungen.
@Gumbo 's Antwort ist eindeutig und umsetzbar, aber verbraucht viel Zeit, wenn die Länge(A) größer als 400 und P größer als 8. Dies ist da dieser Algorithmus ist eine Art brute-forcing mit Leistungen, wie er sagte.
In der Tat, eine sehr schnelle Lösung ist mit dynamische Programmierung.
Gegeben ein array A von positiven ganzen zahlen und eine positive ganze Zahl P, trennen Sie das array A in P nicht-überlappende subarrays, so dass die Differenz zwischen der Summe der einzelnen subarray und die perfekte Summe der subarrays (sum(A)/P) minimal ist.
Halten, dass Ein array hat N Elemente; Q(i,j) bedeutet, dass die Mindest-Maß-Wert, wenn die split die letzten i Elemente von A in j subarrays. D(i,j) bedeutet
(sum(B)-sum(A)/P)^2
wenn array B aus der i~jth Elemente Einer (0<=i<=j<N
).Mindestmaß der Frage ist die Berechnung von Q(N,P). Und wir finden, dass:
So, wie es gelöst werden kann dynamische Programmierung.
Also der Algorithmus Schritt ist:
Funktionierenden code unter (ich habe php-Sprache). Dieser code entscheidet, Teil Menge selbst;
code-Ausgabe wird Teil der Summen, wie da unten
Frage ich mich, ob Folgendes funktionieren würde:
Gehen von der linken Seite, sobald
sum > sigma
, Zweig, in, zwei, eins, darunter der Wert, der drückt ihn über, und eine, die nicht. Rekursiv verarbeiten Daten auf der rechten Seite mitrightSum = totalSum-leftSum
undrightP = P-1
.So, am Anfang, Summe = 60
Dann für
2 4 6 7
, Summe = 19 > sigma, also aufgeteilt in:Dann verarbeiten wir
7 6 3 3 3 4 3 4 4 4 3 3 1
und6 3 3 3 4 3 4 4 4 3 3 1
mitP = 4-1
undsum = 60-12
undsum = 60-19
bzw.Diese Ergebnisse, ich denke, O(P*n).
Kann es ein problem werden, wenn ein 1-oder 2-Werte ist mit Abstand der größte, aber für jeden Wert >= sigma, können wir wohl nur setzen, dass es in seiner eigenen partition (Vorverarbeitung der Arrays zu finden ist diese vielleicht die beste Idee (und reduzieren die Summe angemessen)).
Wenn es funktioniert, sollte es hoffentlich Minimierung der sum-of-squared-error (oder Nähe), die scheint, wie Sie die gewünschten Messen.
Schlage ich vor, einen Algorithmus basiert auf backtracking. Die main-Funktion nach dem Zufallsprinzip wählen Sie ein element aus dem ursprünglichen array und fügt Sie in ein array partitioniert. Für jede addition überprüfen, um zu erhalten eine bessere Lösung als das original. Dies wird erreicht, indem eine Funktion, die berechnet die Abweichung, wobei jedem hinzufügen eines neuen Elements zu der Seite. Wie auch immer, ich dachte, es wäre gut, fügen Sie eine original-Variablen in Schleifen, die können Sie nicht erreichen gewünschten Lösung zwingen wird das Programm beendet. Durch die gewünschte Lösung, die ich Mittel, um fügen Sie alle Elemente mit Bezug auf die Bedingung auferlegt, durch die Bedingung aus wenn.
}
Sie können dies ändern, indem man zuerst wenn ein code Hexe portion mit einer Menge der berechneten Abweichung.
aditional_amount=0
iteration=0
während
{
...
wenn(initial_deviation>Abweichung(difference_vector)+additional_amount)
ExtractFromBackVectorAndPutOnSecondvector(list_vector, vector)
wenn(iteration>max_iteration)
{
iteration=0
aditional_amout+=1/some_constant
}
iteration++
//löschen, die zweite, wenn von der ersten version
}
Dein problem ist sehr ähnlich oder die gleichen wie die, die minimum makespan scheduling problem, je nachdem, wie Sie definieren Ihr Ziel. In dem Fall, dass Sie wollen, um zu minimieren die maximale
|sum_i - sigma|
ist es genau das problem.Als auf die in dem Wikipedia-Artikel, dieses problem ist NP-vollständig für
p > 2
. Graham list-scheduling-Algorithmus ist optimal fürp <= 3
wird, und liefert eine Näherung Verhältnis von2 - 1/p
. Sie können check out Wikipedia für weitere algorithmen und deren Annäherung.Alle algorithmen, die auf dieser Seite sind entweder die Lösung für ein anderes Ziel, falsche/nicht optimal, oder kann verwendet werden, um zu lösen jedes problem in NP 🙂
Dies ist sehr ähnlich zu dem Fall der eindimensionalen bin packing problem, siehe http://www.cs.sunysb.edu/~algorith/files/bin-packing.shtml. In dem dazugehörigen Buch Die Algorithmus-Design-Handbuch, Skienna schlägt eine first-fit decreasing Ansatz. I. e. herauszufinden, Ihre Klassengröße (Mittelwert = sum /N), und reservieren Sie die größte erhaltene Objekt in der ersten bin, die Platz hat für Sie. Entweder bekommt man zu einem Punkt, wo Sie beginnen müssen, die über die Besetzung einer bin, oder wenn du Glück hast bekommst du eine perfekte Passform. Als Skiena Staaten "First-fit-decreasing hat eine intuitive appeal, das packen wir das sperrige Objekte zuerst und die Hoffnung, dass kleine Objekte können füllen die Risse."
Wie eine Vorherige Plakat gesagt, das problem wie es aussieht ist NP-vollständig, so dass du nicht gehst, es zu lösen perfekt in angemessener Zeit, und Sie brauchen, um für die Heuristiken.
Vor kurzem musste ich das und habe wie folgt;
[[sum:0],[sum:0]...[sum:0]]
initial
array.Dies ist der code in JS.
JS:
Können Sie mit dem Max-Flow-Algorithmus.