Heim  >  Artikel  >  Backend-Entwicklung  >  Die Mengenpartitionierung ist NP-vollständig

Die Mengenpartitionierung ist NP-vollständig

王林
王林nach vorne
2023-09-05 15:17:061332Durchsuche

Die Mengenpartitionierung ist NP-vollständig

Übersetzen Sie das Set-Parcel-Problem ins Chinesische. Dies ist ein NP-vollständiges Problem. Die Aufgabe besteht darin, zu bestimmen, ob eine gegebene Menge positiver Ganzzahlen so in zwei Teilmengen unterteilt werden kann, dass ihre Summen gleich sind. NP-vollständig bedeutet, dass kein derzeit bekannter Algorithmus in Polynomzeit alle Fälle lösen kann und die Überprüfung einer möglichen Lösung in Polynomzeit erfolgen sollte. Viele andere NP-vollständige Probleme lassen sich auf das Set-Parcel-Problem reduzieren, was seine rechnerische Komplexität und Bedeutung für das Verständnis der breiteren Klasse NP-vollständiger Probleme demonstriert. Aufgrund seiner Komplexität kann die Lösung umfangreicher Fälle des Set Parcel-Problems einen enormen Zeitaufwand erfordern, was es schwierig macht, effizient eine optimale Lösung zu finden.

Verwendete Methoden

  • Brute Force

  • Backtracking-Algorithmus

Brute Force

Brute Force ist ein unkomplizierter und harmloser algorithmischer Ansatz zur Lösung eines Problems, bei dem jede mögliche Permutation bewertet und die richtige ausgewählt wird. Dabei geht es darum, jede mögliche Permutation effizient aufzuzählen und tatsächlich zu prüfen, ob jede Permutation die Anforderungen des Problems erfüllt. Obwohl der Brute-Force-Ansatz konzeptionell einfach und leicht zu implementieren ist, kann er bei Problemen mit großen Permutationsräumen rechenineffizient und unpraktisch sein.

Unabhängig von seiner Einfachheit kann die Wildkraft eine wichtige Methode für Dinge mit geringem Informationsumfang sein oder wenn der Arrangementraum im Allgemeinen klein und angemessen ist. Sie wird häufig für einfache Dinge, als Muster zur Überprüfung der Richtigkeit oder als Anfangsphase verwendet bevor modernere Berechnungen angewendet werden.

Algorithmus

  • Berechnen Sie die Vollständigkeit aller Komponenten im Set und prüfen Sie, ob sie durch 2 teilbar sind. Wenn nicht, geben Sie „Keine Lösung“ zurück.

  • Initialisieren Sie zwei Bereinigungssätze, Teilmenge 1 und Teilmenge 2.

  • Rufen Sie den rekursiven Arbeitspartitionierungshelfer „partitionHelper“ unter Verwendung der Startmenge S, Teilmenge 1, Teilmenge 2 und der Zielsumme (totalSum / 2) auf.

  • In der Funktion partitionHelper:
  • Überprüfen Sie, ob die Gesamtheit der Komponenten in Teilmenge 1 mit der Zielgesamtheit übereinstimmt. Geben Sie in diesem Fall die Teilmengen 1 und 2 aus und kehren Sie zurück. Wenn die Menge S gelöscht ist, kehre zurück Wählen Sie Komponente x aus S und vertreiben Sie sie aus S.

  • Versuchen Sie, x in Teilmenge1 aufzunehmen und partitionHelper rekursiv mit dem aktualisierten S, Teilmenge1, Teilmenge2 und der Zielsumme aufzurufen.

  • Wenn das Gebot keine große Parzelle findet, schließen Sie x aus Teilmenge 1 aus und versuchen Sie, x in Teilmenge 2 aufzunehmen
  • Rufen Sie die Funktion „partitionHelper“ rekursiv unter Verwendung des neu organisierten S, der Teilmenge 1, der Teilmenge 2 und der Zielsumme auf

  • Wenn in der Rekursion kein wesentliches Segment gefunden wird, geben Sie „Keine Anordnung“ ein.

Beispiel

#include <iostream>
#include <vector>

bool partitionHelper(std::vector<int> S, std::vector<int>& 
subset1, std::vector<int>& subset2, int targetSum) {
   if (targetSum == 0) {
      std::cout << "Subset 1: ";
      for (int num : subset1) {
         std::cout << num << " ";
      }
      std::cout << "\nSubset 2: ";
      for (int num : subset2) {
         std::cout << num << " ";
      }
      return true;
   }

   if (S.empty()) {
      return false;
   }

   int x = S.back();
   S.pop_back();

   subset1.push_back(x);
   if (partitionHelper(S, subset1, subset2, targetSum - x)) {
      return true;
   }
   subset1.pop_back();

   subset2.push_back(x);
   if (partitionHelper(S, subset1, subset2, targetSum - x)) {
      return true;
   }
   subset2.pop_back();

   return false;
}

void partition(const std::vector<int>& S) {
   int totalSum = 0;
   for (int num : S) {
      totalSum += num;
   }
   if (totalSum % 2 != 0) {
      std::cout << "No solution.\n";
      return;
   }

   std::vector<int> subset1, subset2;
   int targetSum = totalSum / 2;

   if (!partitionHelper(S, subset1, subset2, targetSum)) {
      std::cout << "No solution.\n";
   }
}

int main() {
   std::vector<int> set = {1, 2, 3, 4, 5, 6};
   partition(set);
   return 0;
}

Ausgabe

No solution.

Zurückverfolgen

Backtracking ist eine umfassende algorithmische Methode, mit der gezielt nach Lösungen für kombinatorische Probleme gesucht wird. Es handelt sich um eine Art experimentelle Suche, bei der die Berechnung verschiedene mögliche Ergebnisse untersucht, kontinuierlich eine mögliche Anordnung konstruiert und zurückverfolgt, wenn sie erkennt, dass Ebbe und Flut möglich sind. Es kommt nicht zu einer wesentlichen Vereinbarung.

Ein Backtracking-System kann man sich als einen Untersuchungsbaum vorstellen, bei dem jeder Knoten eine in einem bestimmten Schritt getroffene Entscheidung darstellt und die Zweige die möglichen Ergebnisse dieser Entscheidung darstellen. Der Algorithmus durchläuft den Baum tiefenorientiert und untersucht nacheinander jeden Pfad, bis er eine gültige Lösung findet oder alle Möglichkeiten ausschöpft.

Algorithmus

  • Beginnen Sie mit zwei Hohlraummengen, SetA und SetB, um die beiden zu formenden Teilmengen anzugehen.

  • Untersuchen Sie rekursiv alle potenziellen Mischungen von Komponenten aus einem bestimmten Satz, um sich daran zu erinnern, was in SatzA und SatzB enthalten ist

  • Fügen Sie bei jedem Schritt eine Komponente zu SetA hinzu und führen Sie eine Rekursion auf die zusätzlichen Komponenten durch, oder fügen Sie sie zu SetB hinzu und führen Sie eine Rekursion durch

  • Überwachen Sie die Anzahl von SetA und SetB während der Rekursion

  • Wenn der Betrag von SetA zu irgendeinem Zeitpunkt auf den Betrag von SetB ansteigt, bringen Sie Valid auf jeden Fall zurück.

Example

#include <iostream>
#include <vector>

bool isValidSubset(const std::vector<int>& inputSet, int index, int 
setSizeA, int setSizeB) {
   if (index == inputSet.size()) {
      return (setSizeA == setSizeB);
   }

   bool isValid = isValidSubset(inputSet, index + 1, setSizeA + 1, setSizeB);
   isValid |= isValidSubset(inputSet, index + 1, setSizeA, setSizeB + 1);

   return isValid;
}

int main() {
   std::vector<int> inputSet = {1000, 2000, 3000, 4000, 5000};
   bool isValid = isValidSubset(inputSet, 0, 0, 0);
   std::cout << (isValid ? "Valid" : "Misleading") << std::endl;
   return 0;
}

输出

Misleading

结论

本文研究了集合分割问题的NP完备性,该问题包括决定给定的一组正整数是否可以被分割成两个子集,使得它们的和相等。NP完备性意味着没有已知的多项式时间算法可以解决该问题的所有情况,并且验证一个潜在解决方案可以在多项式时间内完成。本文讨论了三种方法来解决这个问题:蛮力法、回溯法和动态规划。由于其复杂性,解决集合分割问题的大规模实例可能需要大量的时间和努力,使得寻找一个理想的解决方案变得具有挑战性。理解集合分割的复杂性很重要,因为它与其他NP完备问题相关,为我们揭示了计算复杂问题的更广泛教训

Das obige ist der detaillierte Inhalt vonDie Mengenpartitionierung ist NP-vollständig. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:tutorialspoint.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen