Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

1

31.05.2016, 21:33

[Graphentheorie] alle kürzesten Zyklen in ungerichtetem Graphen finden

Hallo Leute,

heute mal was Theoretisches. :) Ich möchte alle kleinen Flächen in einem ebenen Polygonnetz finden. Die Punkte sind in einem kleinen ungerichteten Graphen gespeichert. Es gibt keine Schnittpunkte zwischen den Kanten - dafür wird gesorgt! Es sind nicht viele Punkte und es ist nicht Zeitkritisch - Brute-Force ist möglich.

Jeder Knoten hat eine Gerade Anzahl an Nachbarn - der Graph ist also geschlossen. Ich möchte alle kürzesten Zyklen (Flächen) finden. Dazu habe ich mir einen Algorithmus programmiert, der mit Rekursion sämtliche möglichen Zyklen findet und als Mengen ausgibt. Mengen, die mehrmals vorkommen werden auf eine reduziert. Auf Bild_A sind die vom Algorithmus gefundenen Pfade blau, grün und pink eingezeichnet. Der blaue Pfad schließt den grünen und den pinken Pfad ein. Der blaue kann daher gelöscht werden, weil sich seine Fläche aus grün und pink zusammensetzen lässt. Der Algorithmus löscht daher auch alle Mengen, für die es eine Untermenge gibt. Bild_A wird damit richtig analysiert.

Nun habe ich einen Graphen wie in Bild_B zu sehen ist. Da funktioniert das nicht mehr so einfach. Denn blau und pink sind keine Untermengen von grün - wegen Knoten G. Wie muss mein Algorithmus funktionieren, damit das im Allgemeinen funktioniert?

EDIT: Falls wer fragt: Der Ursprung ist dieses Problem.
»CeDoMain« hat folgende Bilder angehängt:
  • Bild_A.png
  • Bild_B.png
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

2

31.05.2016, 23:53

Wenn mehrere Mengen den gleichen Knoten haben, der genau zwei Kanten aufweist, nimmst du die Menge mit der kleinsten Mächtigkeit und verwirfst alle anderen. Sollten sie weitere, derartige Knoten einschließen, musst du die natürlich für zukünftige, ähnliche Überprüfungen ignorieren.
Damit allein kannst du Bild B schon wieder lösen. Allgemein lösen wirst du damit aber nicht können, wenn eine Fläche etwa nur von Vertices eingeschlossen wird, die alle mehr als zwei Kanten haben. Um das zu machen, könntest du die Vertices und deren Kanten, von denen du schon weißt, dass die zu einem Knoten gehören, komplett ignorieren und die Anzahl der Kanten der Vertices, mit denen jene verbunden waren, entsprechend reduzieren.
Doch auch damit wirst du nicht jede Fläche jedes Graphen finden können. Der folgende würde zum Beispiel Probleme machen:

(Link)

Um diesen Fall aufzubröseln, muss man eigentlich gar nicht so viel verändern. Die oben skizzierte Vorgehensweise lässt sich super durchführen, bis nur noch Vertices "interessant/bekannt" sind, die mehr als zwei Kanten haben. Haben wir einen solchen Fall wie in dieser Skizze hier, könntest du das Ergebnis protokollieren, wenn du je einen Vertex einfach mal ignorierst. Aus diesen ganzen Protokollen prüfst du dann wieder auf die minimalen Ergebnisse.
Vielleicht nochmal am Beispiel aus dem Bild:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
1.1) Ignorieren (1)
 .2) Haben nur den Zyklus 2→3→4→2, war unbekannt, also merken und Ende
2.1) Ignorieren (2)
 .2) Haben nur den Zyklus 1→3→4→1, war unbekannt, also merken und Ende
3.1) Ignorieren (3)
 .2) Haben nur den Zyklus 1→2→4→1, war unbekannt, also merken und Ende
4.1) Ignorieren (4)
 .2) Haben die Zyklen 2→3→4→2, 1→3→4→1, 1→2→4→1 und 1→3→2→1, wir kennen schon Zyklen dieser Liste!
 .3) Zyklen aus dieser Liste entfernen, restliche Zyklen darauf prüfen, ob sie irgendeinen Knoten dieser Zyklen enthalten
   -> JA: Entfernen (was in diesem Fall zutrifft)         -> NEIN: Ist unbekannt, also merken und Ende
5) Kein weiterer Knoten verfügbar, also FIN

Und damit sollte sich das eigentlich ganz gut erledigt haben, wenn ich mich jetzt nicht total vertan habe. :crazy:
Das alles setzt natürlich deine Grundlage voraus und ist nur eine Lösung von potentiell sehr vielen. Persönlich würde ich das Problem ganz anders rangehen.

MfG
Check

CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

3

01.06.2016, 02:20

Wenn mehrere Mengen den gleichen Knoten haben, der genau zwei Kanten aufweist, nimmst du die Menge mit der kleinsten Mächtigkeit und verwirfst alle anderen. Sollten sie weitere, derartige Knoten einschließen, musst du die natürlich für zukünftige, ähnliche Überprüfungen ignorieren.
Damit allein kannst du Bild B schon wieder lösen.
Sorry, aber da kann ich nicht folgen. Bei dieser Methode fliegt grün sofort raus, aber dann auch blau oder pink, weil die ja G beide besitzen!?

Allgemein lösen wirst du damit aber nicht können, wenn eine Fläche etwa nur von Vertices eingeschlossen wird, die alle mehr als zwei Kanten haben. Um das zu machen, könntest du die Vertices und deren Kanten, von denen du schon weißt, dass die zu einem Knoten gehören, komplett ignorieren und die Anzahl der Kanten der Vertices, mit denen jene verbunden waren, entsprechend reduzieren.

Das habe ich nicht verstanden! Kannst du kürzere Sätze schreiben oder mal ein Beispiel machen?
Persönlich würde ich das Problem ganz anders rangehen.
Sprich! :) Setzt du beim Graphen an oder beim Polygonnetz? Beides steht zur Verfügung - es gibt keine Kanten mehr die sich schneiden, dafür sorgt das Programm vorher.
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

4

01.06.2016, 03:00

Okay, da habe ich mich vertan. Nach so einer Prüfung ist man doch ziemlich unkonzentriert. :rolleyes:
Vergiss das einfach, ist Nonsens. An sich suchst du nach den Connected Components eines Graphen, was sich mit einer einfachen Tiefensuche auch recht simpel lösen lassen sollte. Da mit Zyklen zu arbeiten fügt unnötige Komplexität hinzu.

MfG
Check

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Checkmateing« (01.06.2016, 03:11)


CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

5

01.06.2016, 03:24

Um die Uhrzeit schreibst du noch Prüfungen!? :D Wo wohnst du denn...

"Connected Components" suche ich nicht, die kann dir dir sogar ohne Computer sagen - der Graph besteht aus einer einzigen. Ich suche stattdessen alle kleinsten Zyklen in dem Graphen. Ich weiß nicht wie ich es besser benennen kann. :| Ich möchte alle Flächen in dem Graphen erfassen, aber keine darf doppelt vorkommen.
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

01.06.2016, 06:53

1) Du gehst alle Knoten (A) durch und für jeden Knoten:
1.0) Erstelle eine leere Liste (Z)
1.1) Suche den jeweils im Uhrzeigersinn nächstgelegenen erreichbaren Knoten (B) (bei welchem Winkel du für diese Suche beginnst ist hierbei total egal), der nicht schon in Liste (Z) ist:
1.2) Packe (B) in (Z)
1.3) Suche den nächsten Knoten Bz derart, dass der Winkel (im Uhrzeigersinn) zwischen der nächsten Kante und der vorherigen Kante minimal ist.
1.4) Packe (Bz) in (Z)
1.5) Gehe zu (Bz) und mache bei 1.3 weiter, bis du wieder beim Knoten (A) ankommst (B==A)
1.6) Packe alle so abgelaufenen Knoten (in Z) als Polygon (P) in eine Ergebnisliste (E)
1.7) Gehe zu 1.1 und mache beim nächsten Knoten in Uhrzeigersinn weiter
2) Sortiere alle Knoten (Z) aller Polygone (P) der Ergebnisliste (E) nach ihrer Nummer aufsteigend (1->4->2 = 1->2->4; 4->2->1 = 1->2->4), bzw. implementier eine equals/hash-Methode in dieser Art
3) Entferne alle dabei entstehenden Duplikate (also fliegt 4->2->1 weg) (mit einem Ergebnis-Set für Polygone und der richtigen equals/hash-Methode passiert das von allein)
Übrig bleiben alle kleinsten Zyklen, bzw. eben alle Polygon-Flächen.

tl;dr: Du gehst jeden Knoten durch und durchläufst ganz stupide *alle* an ihn angrenzenden Polygone durch Durchlaufen der Knoten im Uhrzeigersinn und entfernst hinterher Duplikate.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »BlueCobold« (01.06.2016, 07:10)


CeDoMain

Alter Hase

  • »CeDoMain« ist der Autor dieses Themas

Beiträge: 587

Wohnort: Ilmenau

Beruf: Student für Mechatronik

  • Private Nachricht senden

7

01.06.2016, 16:46

Danke, das hört sich vielversprechend an! Ich habe das gerade auf einem Blatt mal ausprobiert. Dabei habe ich die Form aus dem Anhang verwendet. Gestartet bin ich beim roten Punkt. Dann bin ich wie beschrieben die rote Kette abgegangen, indem ich immer die Winkel genommen habe, die im Uhrzeigersinn gemessen am kleinsten sind. Dann Rücksprung zu 1.1). Muss ich jetzt (Z) löschen? Wenn ich das nicht mache, dann habe ich beim nächsten Polygon noch die Punkte des vorherigen drin...

Dann ist mir noch etwas anderes aufgefallen: Wenn ich bei Rot nach links starte, dann laufe ich die grüne Kette ab. Eigentlich muss ich doch am blauen Punkt in Richtung der blauen Kette einschlagen, aber der Winkel in diese Richtung ist im Uhrzeigersinn gemessen doch größer als der vom blauen Punkt nach unten!? Habe ich vielleicht das mit der Winkelmessung nicht verstanden?
»CeDoMain« hat folgendes Bild angehängt:
  • Skizze.png
Mit freundlichem Gruß
CeDo
Discord: #6996 | Skype: cedomain

Lass solche persönlichen Angriffe lieber bleiben, meine sind härter.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

01.06.2016, 16:58

Statt zu 1.1 geht zu 1.0, ja ;) Das hatte ich nachträglich eingefügt und dann wohl vergessen.
Der grüne Weg ist in der Tat interessant und ist nach dem Algo wirklich ein Ergebnis. Allerdings kannst du das rauswerfen, wenn du die Summe der tatsächlichen Innenwinkel (das, was als innen angenommen wurde) mit aufsummierst und mit dem vergleichst, was hätte als Innenwinkel rauskommen müssen (bei 3 Knoten 1*180, bei 4 Knoten 2*180, bei 5 Knoten 3*180 und so weiter). Ist das tatsächliche Ergebnis größer, ist es kein valides Polygon, sondern nimmt "die Welt außen rundrum" als Polygoninhalt an, was aber offensichtlich verkehrt ist.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

equinox

Frischling

Beiträge: 56

Beruf: Student

  • Private Nachricht senden

9

01.06.2016, 19:35

Ich denke man könnte das auch mit einer Art veränderten A-Stern lösen ( passt nicht so ganz aber wird hoffentlich klar wie ich darauf komme):

Nodes sind deine Punkte, die eine Liste ihrer Nachbarn haben und eine weitere leere Liste, die Parent-Nodes speichern soll.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public ArrayList<Polygon> findMinPolygons(Node polygonNet)
    {
        open = new ArrayList<>();
        closed = new ArrayList<>();
        polygons = new ArrayList<>();
        
        open.add(polygonNet);
        Node current = polygonNet;
        while(!open.isEmpty())
        {
            current = open.get(0);
            open.remove(0);
            closed.add(current);
            
            if(current.parents.size() >= 2)
            {
                polygons.add(polygonFound(current));
            }
            expandNode(current);    
        }
        return polygons;
    }


expandNode() fügt die nicht besuchten Nachbarn zu der OpenList hinzu, wenn dieser noch nicht Besucht ist( wie A-Stern, ohne Heuristik), und fügt den aktuellen Knoten als Parent hinzu.

und die Funktion PolygonFound liefert im Endeffekt eine Liste der Nodes zurück die ein Polygon bilden.
Hierzu wird geprüft, ob ein Node mehrere Parent-Nodes hat und wenn ja, befindet sich dort ein Polygon.

polygonFound() geht einfach die Parents durch bis es keine mehr gibt, "fügt" diese in das Polygon ein (hab es als Liste modelliert) und löscht auf dem weg dahin alle besuchten Parent-Nodes.

Allerdings ist das nur eine Idee, habe es kurz getestet, müsste aber größere Probleme modellieren um sicher zu gehen.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

10

01.06.2016, 20:09

Das findet aber vermutlich entweder nicht alle Polygone oder aber es findet nicht nur die kleinesten Zyklen, sondern alle Zyklen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige