AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Erkennen von Zahlenpaaren

Ein Thema von lowmax_5 · begonnen am 8. Okt 2015 · letzter Beitrag vom 9. Okt 2015
Antwort Antwort
Seite 2 von 3     12 3      
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#11

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 14:42
Mhm, auf den ersten Blick sah es nach Partition aus, allerdings scheinst du ja eine passende Partition zu haben.
Ich hätte es eher als Rucksackproblem identifiziert, wobei es ja letztlich auf dasselbe herausläuft: Beide sind NP-vollständig.

Mein Lösungsansatz ist ausgehend von dieser Idee: Mal angenommen, es gäbe nur Kombinationen der Länge 2. Dann wäre es ja einfach: Man subtrahiert einfach alle Zahlen aus Menge1 von allen Zahlen aus Menge2. Dann muss man nur noch prüfen, welche dieser Differenzen auch tatsächlich in Menge1 liegen. Schon hat man alle gültigen Paare.

Wenn man mehr als zwei Elemente pro Kombination zulässt, muss man den Ansatz etwas verallgemeinern: Man muss nun für jede Differenz schauen, ob sie wiederum durch eine Kombination von Elementen aus Menge1 gebildet werden kann. Das kann man wieder mit dem gleichen Algorithmus machen. So macht man es iterativ immer weiter, bis man am Ende Summen hat, die man mit einem einzelnen Element erfüllen kann. Der Trick ist, sich für jede Zwischensumme immer die kürzeste, bereits gefundene Kombination zu merken (Prinzip der Dynamischen Programmierung). Da die Kombinationen immer nur länger werden können, ist die erste gefundene Kombination automatisch immer auch die kürzeste.

Ich habe das mal als Proof-of-Concept implementiert. TCombinationTable sollte man in einer richtigen Implementierung als Hashtable implementieren, dazu war ich jetzt aber zu faul.

Das Programm gibt allerdings immer nur die kürzeste Kombination aus, nicht, ob es noch weitere Kombinationen gibt. Das wäre IMO nur noch mit Brute-Force zu machen.

Beispiel Ein- und Ausgabe:
Delphi-Quellcode:
PARTS: array [0..8] of Integer = (2,6,7,1,6,15,7,4,1);
SUMS: array [0..3] of Integer = (16,13,9,11);
Code:
16 = 15 + 1
13 = 7 + 6
9 = 7 + 2
11 = 7 + 4
Delphi-Quellcode:
PARTS: array [0..16] of Integer = (2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
SUMS: array [0..6] of Integer = (1,2,3,16,13,9,11);
Code:
2 = 2
1 = 1
3 = 2 + 1
9 = 2 + 1 + 2 + 1 + 2 + 1
11 = 1 + 1 + 2 + 1 + 2 + 1 + 2 + 1
13 = 1 + 1 + 1 + 1 + 2 + 1 + 2 + 1 + 2 + 1
16 = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 2 + 1 + 2 + 1 + 2 + 1
Scheint zu funktionieren.

Edit: Habe noch ein paar Fehler in meinem Code korrigiert, wegen denen die Laufzeit deutlich schlechter war als nötig.
Angehängte Dateien
Dateityp: pas combination.pas (6,5 KB, 2x aufgerufen)

Geändert von Namenloser ( 9. Okt 2015 um 20:16 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von JasonDX
JasonDX
(CodeLib-Manager)

Registriert seit: 5. Aug 2004
Ort: München
1.062 Beiträge
 
#12

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 14:43
1. Bilde Summen Menge1 und und Menge2 ==> Wenn gleich, mache weiter
2. Nun alle Permutationen aus Menge1 erzeugen und Summen bilden
3. Ist die Summe der Permutation in Menge2 enthalten => Wenn Ja=gültig, wenn Nein dann löschen
4. Nun alle Kombinationen bilden, die auf die Gesamtsumme kommen. ==> Diese Kombinationen markieren
5. Sortieren nach den einfachsten Kombinationen ( Am wenigsten summierende Elemente)
Fertig!

Kann das funktionieren? Was meint Ihr dazu?
Du wirst bei 2. scheintern. Nicht bei der Implementierung, sondern bei der Laufzeit.

Bau die Lösung schrittweise auf, und wirf nicht funktionierende Lösungen so schnell wie möglich weg.
Mike
Passion is no replacement for reason
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#13

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 15:30
Mh habe mal schnell was zusammengetippt (Ist in keinster Weise perfekt, aber funktioniert schnell und ohne Probleme).
Es geht in erster Linie ums Prinzip.

Ist jetzt allerdings in C#:

Code:
class Program
{
   private static int GetMaxFittingValueIndex(List<int> list, int DestValue)
   {
      int currIdx = 0;
      for (int i=list.Count-1; i >= 0; i--)
      {
         if (DestValue - list[i] == 0)
            return i;
         else
         if ((DestValue - list[i] > 0) && (list[i] > list[currIdx]))
            currIdx = i;
      }

      return currIdx;
   }

   static void Main(string[] args)
   {
      List<int> MengeA = new List<int>(new int[] { 2, 6, 7, 1, 6, 15, 7, 4, 1 });
      List<int> MengeB = new List<int>(new int[] { 16, 13, 9, 11 });
      Dictionary<int, List<int>> SummenMengeC = new Dictionary<int, List<int>>();

      Console.Write("MengeA: ");
      for (int i = 0; i < MengeA.Count; i++)
         Console.Write(MengeA[i].ToString()+",");
      Console.WriteLine();

      Console.Write("MengeB: ");
      for (int i = 0; i < MengeB.Count; i++)
         Console.Write(MengeB[i].ToString()+",");
      Console.WriteLine();

      MengeA.Sort();
      for (int i=0; i < MengeB.Count; i++)
      {
         List<int> currSummeList = new List<int>();
         int currSumme = 0;
         while (currSumme < MengeB[i])
         {
            int idx = GetMaxFittingValueIndex(MengeA, MengeB[i] - currSumme);
            currSumme += MengeA[idx];
            currSummeList.Add(MengeA[idx]);
            MengeA.RemoveAt(idx);
         }

         SummenMengeC.Add(MengeB[i], currSummeList);
      }

      Console.WriteLine();
      Console.WriteLine("Ergebnis:");

      foreach(int zahl in SummenMengeC.Keys)
      {
         Console.Write(zahl.ToString() + " = ");
         for (int i=0; i < SummenMengeC[zahl].Count; i++)
         {
            if (i < SummenMengeC[zahl].Count - 1)
               Console.Write(SummenMengeC[zahl][i].ToString() + "+");
            else
               Console.Write(SummenMengeC[zahl][i].ToString());
         }
         Console.WriteLine();
      }

      Console.ReadLine();
   }
}
Habe ich was nicht beachtet? Bin mir nicht sicher ob das immer die beste Lösung erzeugt, könnte es mir aber vorstellen.
Irgendwelche Gedanken dazu?
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General ( 9. Okt 2015 um 15:33 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#14

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 15:40
Weiß nicht, ob ich deinen Code richtig verstehe, aber ich glaube, der findet nicht immer eine Lösung:

Probier mal
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16 });
Ist aber eine gängige, schnelle Näherungslösung für das Rucksackproblem, soweit ich weiß.
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#15

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 15:41
Weiß nicht, ob ich deinen Code richtig verstehe, aber ich glaube, der findet nicht immer eine Lösung:

Probier mal
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16 });
Ist aber eine gängige, schnelle Näherungslösung für das Rucksackproblem, soweit ich weiß.
Vorgabe ist dass die Summe beider Mengen gleich ist. Das ist bei deinem Beispiel nicht der Fall.

Ich nehme mir nacheinander jede Zahl aus der 2. Menge und suche aus der ersten Menge die größten Zahlen mit denen ich die Summe bilden kann.

16:
Größte Zahl <= 16 ist die 15 => 15 zur Summe hinzufügen und aus Menge1 entfernen, 1 ist übrig
Größte Zahl <= 1 ist die 1 => 1 zur Summe hinzufügen und aus Menge1 entfernen, 0 ist übrig => fertig

13:
Größte Zahl <= 13 ist die 7 => 7 zur Summe hinzufügen und aus Menge1 entfernen, 6 ist übrig
Größte Zahl <= 6 ist die 6 => 6 zur Summe hinzufügen und aus Menge1 entfernen, 0 ist übrig => fertig

usw.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

Geändert von Neutral General ( 9. Okt 2015 um 15:45 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#16

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 15:50
Vorgabe ist dass die Summe beider Mengen gleich ist. Das ist bei deinem Beispiel nicht der Fall.
Hmm, aber ändert das was?
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16, 5, 5, 5});
Hier sind die Summen gleich, die Lösung für die 16 wird meines Erachtens aber trotzdem nicht gefunden.
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#17

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 15:56
Vorgabe ist dass die Summe beider Mengen gleich ist. Das ist bei deinem Beispiel nicht der Fall.
Hmm, aber ändert das was?
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16, 5, 5, 5});
Hier sind die Summen gleich, die Lösung für die 16 wird meines Erachtens aber trotzdem nicht gefunden.
Aber hier ist ja auch generell keine Lösung möglich oder?
Oder dürfen die Summen "mit zurücklegen" gebildet werden? Weil ansonsten fällt nach 16=5+5+6 der Rest so oder so flach.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#18

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 16:07
Oder dürfen die Summen "mit zurücklegen" gebildet werden? Weil ansonsten fällt nach 16=5+5+6 der Rest so oder so flach.
Also ich habe das zumindest so verstanden. Aber auch, wenn man "Zurücklegen" nicht erlaubt, bezweifle ich, dass es immer geht. Z.B. bei:
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16, 20 });
Gut, da könnte man jetzt vielleicht sagen, MengeB muss auch absteigend sortiert sein. Habe ich jetzt zugegeben noch kein Gegenbeispiel für gefunden, aber es würde mich doch wundern, wenn es keines gäbe.

Geändert von Namenloser ( 9. Okt 2015 um 16:10 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#19

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 16:17
Oder dürfen die Summen "mit zurücklegen" gebildet werden? Weil ansonsten fällt nach 16=5+5+6 der Rest so oder so flach.
Also ich habe das zumindest so verstanden. Aber auch, wenn man "Zurücklegen" nicht erlaubt, bezweifle ich, dass es immer geht. Z.B. bei:
Code:
List<int> MengeA = new List<int>(new int[] { 5, 5, 5, 6, 15 });
List<int> MengeB = new List<int>(new int[] { 16, 20 });
Gut, da könnte man jetzt vielleicht sagen, MengeB muss auch absteigend sortiert sein. Habe ich jetzt zugegeben noch kein Gegenbeispiel für gefunden, aber es würde mich doch wundern, wenn es keines gäbe.
Ja da hast du Recht. Aber mit absteigender Sortierung gehts wieder
Wie gesagt: Ich hab selbst keinen Beweis dass das immer so funktioniert. Und wenn es "mit zurücklegen" ist, dann ist mein Code eh an der Aufgabenstellung vorbei
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#20

AW: Erkennen von Zahlenpaaren

  Alt 9. Okt 2015, 16:57
Habe doch noch eins gefunden:
Code:
List<int> MengeA = new List<int>(new int[] { 13, 10, 4 });
List<int> MengeB = new List<int>(new int[] { 14, 13 });
Oder auch
Code:
List<int> MengeA = new List<int>(new int[] { 13, 10, 4, 1 });
List<int> MengeB = new List<int>(new int[] { 14, 13, 1 });
Also ohne Backtracking wird es nicht gehen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:57 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz