2016-08-03 22 views
6

gleich ich die Gleichung wie diese gegeben habe:Ersetzen Betreiber der Gleichung, so dass die Summe auf Null

n = 7 
1 + 1 - 4 - 4 - 4 - 2 - 2 

Wie kann ich Bediener optimal ersetzen, so dass die Summe der Gleichung gleich Null oder Drucken -1. Ich denke an einen Algorithmus, aber es ist nicht optimal. Ich habe eine Idee, alle Fälle mit Komplexität O(n*2^n), aber (n < 300) bruteforce.

Hier ist der Link des Problems: http://codeforces.com/gym/100989/problem/M.

+0

Eine Möglichkeit, den Suchbaum bei Rückzieher könnte zu beschneiden zu erkennen, dass '+ 4 - 4' gleich ist wie '- 4 + 4'. –

+0

Ergreifen Sie die Gesamtparität, wenn es sich um einen ungeraden Druck -1 handelt. – Vesper

+0

Nein, Zahlen sind '1 <= x <300' – user2660964

Antwort

1

Hier ist die Implementierung in C++:

unordered_map <int, int> M, U; 
unordered_map<int, int>::iterator it; 
int a[] = {1, -1, 4, -4}; 

int solve() { 
    for(int i = 0; i < n; ++i) { 
     if(i == 0) M[a[i]] = 1; 
     else { 
      vector <pair <int, int>> vi; 
      for(it = M.begin(); it != M.end(); ++it) { 
       int k = it->first, d = it->second; 
       vi.push_back({k + a[i], d}); 
       vi.push_back({k - a[i], d + 1}); 
      } 
      for(int j = 0; j < vi.size(); ++j) M[vi[j].first] = MAXN; 
      for(int j = 0; j < vi.size(); ++j) { 
       M[vi[j].first] = min(M[vi[j].first], vi[j].second); 
      } 
     } 
    } 
    return (M[0] == 0 ? -1 : M[0] - 1); 
} 
0

Was kann ich mir vorstellen:

Sie die ursprüngliche Gleichung berechnen. Dies ergibt -14. Jetzt sortieren Sie die Zahlen (unter Berücksichtigung ihrer + oder -) Wenn die Gleichung eine negative Zahl ergibt, suchen Sie nach den größten Zahlen, um die Gleichung zu beheben. Wenn eine Zahl zu groß ist, überspringen Sie sie.

orig_eq = -14

Nach dem Sortieren:

-4, -4, -4, -2, -2, 1, 1

Sie Schleife über diese und wählen jede Zahl, wenn die Gleichung orig_eq - aktuelle Zahl ist näher bei Null. Auf diese Weise

Sie können jede Nummer wählen Sie das Zeichen der

+0

Was ist die Komplexität? – user2660964

+0

Wie funktioniert dieser Algorithmus für "5-4-3 + 3-3"? Die Summe ist -2, aber Sie können eine einzelne Zahl nicht ändern, um sie näher an 0 zu bringen. Aber 5 + 4-3-3-3 ist 0. –

+0

Das Partitions-Problem ist NP-vollständig, also ist es sehr unwahrscheinlich, dass es eine gibt garantierte polynomielle Lösung. –

5

ändern Sie diese mit dynamischer Programmierung lösen können. Halten Sie eine Karte aller möglichen Teilsummen (Abbildung auf die minimale Anzahl von Änderungen, diese Summe zu erreichen), und dann aktualisieren sie eine Nummer zu einem Zeitpunkt,

Hier ist eine kurze Python Lösung:

def signs(nums): 
    xs = {nums[0]: 0} 
    for num in nums[1:]: 
     ys = dict() 
     for d, k in xs.iteritems(): 
      for cost, n in enumerate([num, -num]): 
       ys[d+n] = min(ys.get(d+n, 1e100), k+cost) 
     xs = ys 
    return xs.get(0, -1) 

print signs([1, 1, -4, -4, -4, -2, -2]) 

In Theorie hat im schlimmsten Fall exponentielle Komplexität (da sich die Anzahl der Partialsummen bei jedem Schritt verdoppeln kann). Wenn jedoch (wie hier) die gegebenen Zahlen immer (begrenzt) kleine Inte sind, dann wächst die Anzahl der Teilsummen linear, und das Programm arbeitet in O (n^2) -Zeit.

Eine etwas optimierte Version verwendet ein sortiertes Array von (Zwischensumme, Kosten) anstelle eines Diktats. Man kann Teilmengen, die zu groß oder zu klein sind, verwerfen (was es unmöglich macht, bei 0 zu enden, vorausgesetzt, dass alle verbleibenden Elemente zwischen -300 und +300 liegen). Dies läuft ungefähr doppelt so schnell ab und ist eine natürlichere Implementierung, um für eine maximale Geschwindigkeit in eine Sprache auf niedrigerer Ebene als Python zu portieren.

def merge(xs, num): 
    i = j = 0 
    ci = 0 if num >= 0 else 1 
    cj = 0 if num < 0 else 1 
    num = abs(num) 
    while j < len(xs): 
     if xs[i][0] + num < xs[j][0] - num: 
      yield (xs[i][0] + num, xs[i][1] + ci) 
      i += 1 
     elif xs[i][0] + num > xs[j][0] - num: 
      yield (xs[j][0] - num, xs[j][1] + cj) 
      j += 1 
     else: 
      yield (xs[i][0] + num, min(xs[i][1] + ci, xs[j][1] + cj)) 
      i += 1 
      j += 1 
    while i < len(xs): 
     yield (xs[i][0] + num, xs[i][1] + ci) 
     i += 1 

def signs2(nums): 
    xs = [(nums[0], 0)] 
    for i in xrange(1, len(nums)): 
     limit = (len(nums) - 1 - i) * 300 
     xs = [x for x in merge(xs, nums[i]) if -limit <= x[0] <= limit] 
    for x, c in xs: 
     if x == 0: return c 
    return -1 

print signs2([1, 1, -4, -4, -4, -2, -2]) 
+0

Die Kosten sollten bei jedem Tausch um 1 steigen, ich lese die 1 hier nicht in 'Kosten'. – Vesper

+0

@Vesper Ich gebe zu, der Code ist ein wenig tricksy, aber Kosten = 0 für num und Kosten = 1 für -num. –

+0

Beeindruckend. Und mit Zahlen unter 300 wird die Größe von "Ys" niemals 180000 überschreiten, also ist es machbar. Die Gesamtkomplexität ist im ungünstigsten Fall 180000 * n, daher denke ich, dass dies mit Vorüberprüfungen wie "wenn die Summe der Zahlen ungerade ist, Rückgabe von -1" und "wenn' d + n "die Summe/2 durch Modul überschreitet, optimiert werden sollte , füge nicht zu "ys" hinzu. – Vesper