Anzahl der Löcher in einem Polygon

11

Das Problem : Zählen Sie die Anzahl der Löcher in einem verbundenen Polygon. Die Konnektivität des Polygons wird durch die Bedingung garantiert, dass jedes Dreieck in der Eingabetriangulation mindestens eine Seite mit einem anderen Dreieck teilt und dass es nur einen solchen verbundenen Satz von Dreiecken gibt.

Die Eingabe ist eine Liste Lvon nPunkten in der Ebene und eine Liste Tvon 3 Tupeln mit Einträgen von 0...n-1. Für jedes Element im TTupel (t_1,t_2,t_3)stehen die drei Eckpunkte (aus der Liste L) eines Dreiecks in der Triangulation. Beachten Sie, dass dies eine Triangulation im Sinne einer "Polygon-Triangulation" ist , da sich in Tdieser Überlappung niemals zwei Dreiecke befinden . Eine zusätzliche Bedingung ist, dass Sie die Eingabe nicht bereinigen müssen Lund Tkeine Wiederholungen enthalten.

Beispiel 1 : Wenn L = {{0,0},{1,0},{0,1},{1,2}}und T = {{0,1,2},{1,2,3}}dann hat das angegebene Polygon eine Lochanzahl von 0.

Abbildung 1

Beispiel 2 : Wenn L = {{0,0},{1,0},{2,0},{2,1},{2,2},{1,2},{0,2},{0,1},{.5,.5},{1.5,.5},{1.5,1.5},{.5,1.5}}und T = {{5,6,11},{5,10,11},{4,5,10},{3,8,10},{2,3,9},{2,8,9},{1,2,8},{0,1,8},{0,8,11},{0,7,11},{6,7,11},{3,4,10}}dann sollte die Polygoneingabe eine Ausgabe von 2 ergeben.

Figur 2

Die Aufgabe besteht darin, das kürzeste Programm (oder die kürzeste Funktion) zu schreiben, das Lund Tals Eingabe verwendet und die Anzahl der Löcher zurückgibt. Der 'Gewinner' wird als Eintrag mit der geringsten Anzahl von Zeichen anerkannt (vorläufiges Enddatum 1. Juni).

Beispiel für eine Eingabeformatierung (beachten Sie die Indizierung 0):

0,0
1,0
0,1
1,2
0,1,2
1,2,3    
Kaya
quelle
1
"Die Konnektivität des Polygons wird durch die Bedingung garantiert, dass jedes Dreieck in der Eingabetriangulation mindestens eine Seite mit einem anderen Dreieck teilt." -- Nein. Das ist keine ausreichende Bedingung. Nehmen Sie zum Beispiel T=1,2,3/1,2,4/5,6,7/5,6,8. Jedes Dreieck teilt eine Kante mit einem anderen Dreieck, aber die Triangulation wird getrennt
John Dvorak
Dürfen wir annehmen, dass die Eingabe eine gültige partielle Triangulation darstellt (keine zwei Dreiecke überlappen sich und kein Dreieck ist zweimal vorhanden) und die Triangulation verbunden ist?
John Dvorak
Dürfen wir auch annehmen, dass der Eingang in dem Sinne kantenverbunden ist, dass es nicht möglich ist, eine endliche Menge von Punkten zu entfernen, um die Form getrennt zu machen? (Beispiel: T=1,2,3/1,4,5ist verbunden, aber nicht kantenverbunden)
John Dvorak
2
Ich bin mir nicht sicher, warum dieses Geschäft mit Enddaten in letzter Zeit aufgetaucht ist. Sie können die akzeptierte Antwort ändern, sodass Sie kein Enddatum festlegen müssen. Es ist vernünftig, sich vorzustellen, dass Sie eine Woche warten müssen, bevor Sie eine Antwort auswählen, um die Leute nicht zu erschrecken, dass die erste Antwort unschlagbar ist. Solange Sie jedoch auf der Website aktiv sind, können Sie die ausgewählte Antwort ändern wenn jemand einen besseren postet. Relevante Meta-Diskussionen sind meta.codegolf.stackexchange.com/q/542/194 und meta.codegolf.stackexchange.com/q/193/194
Peter Taylor

Antworten:

5

GolfScript (23 Zeichen)

~.{2*2/~}%{$}%.&,@@+,-)

Nimmt das Eingabeformat mit GolfScript-Array-Notation und Anführungszeichen (oder Integralkoordinaten) an. Z.B

$ golfscript codegolf11738.gs <<<END
[["0" "0"] ["1" "0"] ["2" "0"] ["2" "1"] ["2" "2"] ["1" "2"] ["0" "2"] ["0" "1"] [".5" ".5"] ["1.5" ".5"] ["1.5" "1.5"] [".5" "1.5"]] [[5 6 11] [5 10 11] [4 5 10] [3 8 10] [2 3 9] [2 8 9] [1 2 8] [0 1 8] [0 8 11] [0 7 11] [6 7 11] [3 4 10]]
END
2

( Online-Äquivalent )

oder

$ golfscript codegolf11738.gs <<<END
[[0 0] [1 0] [0 1] [1 2]] [[0 1 2] [1 2 3]]
END
0

( Online-Äquivalent )

Peter Taylor
quelle
5

Python, 71

Was folgt, ist ein Programm (keine Funktion ), das die gewünschte Anzahl berechnet.

len(set().union(*(map(frozenset,zip(t,t[1:]+t))for t in T)))-len(L+T)+1

Anwendungsbeispiel:

>>> L = ((0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,1),(.5,.5),(1.5,.5),(1.5,1.5),(.5,1.5))
>>> T = ((5,6,11),(5,10,11),(4,5,10),(3,8,10),(2,3,9),(2,8,9),(1,2,8),(0,1,8),(0,8,11),(0,7,11),(6,7,11),(3,4,10))
>>> len(set().union(*(map(frozenset,zip(t,t[1:]+t))for t in T)))-len(L+T)+1
2
Stellen Sie Monica wieder her
quelle
+1 für die Verwendung des Splat, die Verwendung von Frozenset anstelle von Sortierung, Zip (kann nicht sagen, dass ich es jemals zuvor verwendet habe, muss mich kennenlernen.)
Kaya
3

APL, 36

{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}

Die Funktion wird Lals linkes und Tals rechtes Argument verwendet .

Beispielsweise:

      L←(0 0)(1 0)(0 1)(1 2)
      T←(0 1 2)(1 2 3)
      L{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}T
0
      L←(0 0)(1 0)(2 0)(2 1)(2 2)(1 2)(0 2)(0 1)(.5 .5)(1.5 .5)(1.5 1.5)(.5 1.5)
      T←(5 6 11)(5 10 11)(4 5 10)(3 8 10)(2 3 9)(2 8 9)(1 2 8)(0 1 8)(0 8 11)(0 7 11)(6 7 11)(3 4 10)
      L{1+(⍴⊃∪/{{⍵[⍋⍵]}¨,/3 2⍴⍵,⍵}¨⍵)-⍴⍺,⍵}T
2

Erklärung von rechts nach links:

  • ⍴⍺,⍵verkettet die beiden Eingabevektoren und gibt ihre Länge zurück ( V + F)
  • Schritt in den nächsten Block:
    • ¨⍵ wendet die Funktion links auf jedes Element des rechten Arguments an und gibt das Ergebnis zurück
    • ⍵,⍵ Gibt das richtige Argument zurück, das mit sich selbst verknüpft ist
    • 3 2⍴formt das Vektorargument in drei Paare. In diesem Fall werden die ersten und zweiten, dritten und ersten sowie zweiten und dritten Elemente des Vektors miteinander gepaart.
    • ,/ verbindet das Vektorargument miteinander
    • ⍵[⍋⍵] sortiert das richtige Argument
    • ∪/ filtert alle Duplikate heraus
    • ⍴⊃ verwandelt einen verschachtelten Skalar in einen Vektor und gibt dessen Länge zurück.
    • Die gesamte Funktion gibt die Anzahl der Kanten in der Form zurück ( E)
  • 1 ist selbsterklärend (ich hoffe ...)

Die gesamte Funktion kehrt dann zurück 1+E-(V+F), oder 1-(F+V-E).

Flüchtigkeit
quelle
Ziemlich genau das, was meine GolfScript-Lösung macht. Ich bin überrascht, dass es so viel länger ist als GolfScript.
Peter Taylor
@PeterTaylor Ich war überrascht, dass Ihre GolfScript-Lösung so viel kürzer war! (Aber andererseits ist es GolfScript)
Volatility
2

Mathematica, 93 (noch nicht viel Golf gespielt)

f[l_, t_] :=  Max@MorphologicalComponents[Erosion[Graphics[
                                                        GraphicsComplex[l, Polygon[t + 1]]], 1]] - 1

(Leerzeichen aus Gründen der Übersichtlichkeit hinzugefügt)

Testen:

f[{{0, 0}, {1, 0}, {0, 1}, {1, 2}}, {{0, 1, 2}, {1, 2, 3}}]
(*
 -> 0
*)

{l, t} = {{{0, 0}, {1,   0}, {2,    0}, {2,     1}, {2,    2}, {1, 2}, {0, 2}, 
           {0, 1}, {.5, .5}, {1.5, .5}, {1.5, 1.5}, {.5, 1.5}}, 

           {{5, 6, 11}, {5, 10, 11}, {4, 5, 10}, {3, 8, 10}, {2, 3,  9}, 
            {2, 8,  9}, {1,  2,  8}, {0, 1,  8}, {0, 8, 11}, {0, 7, 11}, {6, 7, 11}, {3, 4, 10}}};
f[l, t]
 (*
  -> 2
 *)
Dr. Belisarius
quelle
Beruht dies nicht auf den Dreiecken oder Löchern mit einer bestimmten minimalen Größe (das Argument dazu Erosion)?
John Dvorak
@JanDvorak Vielleicht irre ich mich, aber ich denke, wenn Sie keine Arithmetik mit unendlicher Genauigkeit verwenden, funktioniert jede Lösung, bis Sie eine bestimmte Mindestgröße erreicht haben (Sie müssen entscheiden, ob drei Punkte ausgerichtet sind oder nicht). Es ist nur so, dass bei dieser Art von Lösung das Problem explizit angegeben wird.
Dr. Belisarius
Wenn Sie den topologischen Ansatz verwenden, müssen Sie dies nicht tun. Wenn drei Punkte kollinear sind, benötigen Sie dort ein Dreieck mit der Nullfläche - andernfalls haben Sie ein Loch.
John Dvorak
@ Belisarius. Hier ist die Antwort, die ich vom technischen Support von Wolfram bezüglich der Diskrepanz zwischen unseren Ergebnissen erhalten habe: "Hallo - Vielen Dank für Ihre E-Mail. Ich habe bestätigt, dass Ihr Code unter Mac und Windows unterschiedliche Ergebnisse liefert. Ich glaube nicht, dass dies beabsichtigt ist Ich habe bei unseren Entwicklern einen Bericht zu diesem Problem eingereicht. Ich werde sicher alle nützlichen Informationen weitergeben, die ich von unseren Entwicklern zu diesem Problem erhalte. Bitte lassen Sie mich wissen, wenn Sie weitere Fragen haben. ... Technischer Support Wolfram Research , Inc. "
DavidC
@DavidCarraher "Ja, ich habe weitere Fragen:
Dr. Belisarius
2

Ruby, 239 Zeichen (227 Körper)

def f t
e=t.flat_map{|x|x.permutation(2).to_a}.group_by{|x|x}.select{|_,x|x.one?}.keys
n=Hash[e]
(u,n=n,n.dup;e.map{|x|a,b=*x;n[a]=n[n[a]]=n[b]})until n==u
n.values.uniq.size+e.group_by(&:last).map{|_,x|x.size}.reduce(-1){|x,y|x+y/2-1}
end

Beachten Sie, dass ich nur die Topologie betrachte. Ich verwende die Scheitelpunktpositionen in keiner Weise.

Anrufer (erwartet T im Mathematica- oder JSON-Format):

input = gets.chomp
input.gsub! "{", "["
input.gsub! "}", "]"
f eval(input)

Prüfung:

f [[0,1,2],[1,2,3]]
#=> 0
f [[5, 6, 11], [5, 10, 11], [4, 5, 10], [3, 8, 10], [2, 3, 9], [2, 8, 9], [1, 2, 8], [0, 1, 8], [0, 8, 11], [0, 7, 11], [6, 7, 11], [3, 4, 10]]
#=> 2
f [[1,2,3],[3,4,5],[5,6,1],[2,3,4],[4,5,6],[6,1,2]]
#=> 1
John Dvorak
quelle
Ja, ein euler charakteristischer Ansatz. So habe ich es in Python gemacht.
Kaya
2
@ Kaya. (Siehe Ei von Columbus en.wikipedia.org/wiki/Egg_of_Columbus ) Sobald jemand eine Eulersche Antwort auf Ihre Frage gegeben hat, steigt die Wahrscheinlichkeit, dass andere folgen, stark an. Ich kann Ihnen versichern, dass es weitaus schwieriger und erfreulicher ist, den Ansatz selbst zu entdecken und erst danach die Verbindung zu Eulers Arbeit mit Polyedern herzustellen.
DavidC
2

Mathematica 76 73 72 67 62

Nach vielen Experimenten wurde mir klar, dass die genaue Position der Eckpunkte keine Rolle spielt, und so stellte ich das Problem mit Graphen dar. Die wesentlichen Invarianten, die Anzahl der Dreiecke, Kanten und Eckpunkte blieben unveränderlich (vorausgesetzt, Linienkreuzungen wurden vermieden).

Es gab zwei Arten von internen "Dreiecken" in der Grafik: Diese waren vermutlich ein Gesicht, dh ein "gefülltes" Dreieck, und diejenigen, bei denen es keine gab. Die Anzahl der Innenflächen hatte keine Beziehung zu den Kanten oder Eckpunkten. Das bedeutete, dass das Stechen von Löchern in vollständig "gefüllten" Diagrammen nur die Anzahl der Flächen reduzierte. Ich spielte systematisch mit Variationen zwischen Dreiecken und verfolgte die Flächen, Eckpunkte und Kanten. Schließlich wurde mir klar, dass die Anzahl der Löcher immer gleich 1 - # Gesichter - # Eckpunkte + # Kanten war. Es stellte sich heraus, dass dies 1 minus der Euler-Charakteristik war (von der ich nur im Zusammenhang mit regulären Polyedern gewusst hatte (obwohl die Länge der Kanten eindeutig keine Bedeutung hatte.

Die folgende Funktion gibt die Anzahl der Löcher zurück, wenn die Eckpunkte und Dreiecke eingegeben werden. Im Gegensatz zu meiner früheren Einreichung ist kein Scan eines Bildes erforderlich. Sie können es sich als 1 - Eulers Charakteristik Fvorstellen, dh 1 - (F + V - E) wobei V= # Gesichter, = # Eckpunkte, E= # Kanten. Die Funktion gibt die Anzahl der Löcher unter 1 - (F + V -E)Berücksichtigung der tatsächlichen Flächen (Dreiecke) und Eckpunkte zurück.

Es kann leicht gezeigt werden, dass das Entfernen eines Dreiecks an der Außenseite des Komplexes keinen Einfluss auf die Euler-Charakteristik hat, unabhängig davon, ob es eine oder zwei Seiten mit anderen Dreiecken teilt.

Hinweis: Die Kleinbuchstaben vwerden anstelle Lder ursprünglichen Formulierung verwendet. das heißt, es enthält die Eckpunkte selbst (nicht V, die Anzahl der Eckpunkte)

fwird für die Taus der Originalformulierung verwendete verwendet; Das heißt, es enthält die Dreiecke, die als geordnetes Dreifach der Scheitelpunktindizes dargestellt werden.

Code

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&

(Vielen Dank an Mr. Wizard für das Rasieren von 5 Zeichen durch Aufheben der Ersatzregel.)


Beispiel 1

v = {{0, 0}, {1, 0}, {0, 1}, {1, 2}}; f = {{0, 1, 2}, {1, 2, 3}};

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&[v, f]

0

Null Löcher.


Beispiel 2

v = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1} , {.5, .5}, {1.5, .5}, {1.5, 1.5}, {.5, 1.5}}; f = {{5, 6, 11}, {5, 10, 11}, {4, 5, 10}, {3, 8, 10}, {2, 3, 9}, {2, 8, 9} , {1, 2, 8}, {0, 1, 8}, {0, 8, 11}, {0, 7, 11}, {6, 7, 11}, {3, 4, 10}};

z=Length;1-z@#2-z@#+z[Union@@(Sort/@{#|#2,#2|#3,#3|#}&@@@#2)]&[v, f]

2

Somit sind 2 Löcher in Beispiel 2.

DavidC
quelle
Rasteren Sie im Grunde die Triangulation und speichern eine Grafikbibliothek auf diesem Bild? Scheitert das nicht, wenn ein Loch zu klein ist?
John Dvorak
1
Ihr zweites Beispiel gibt hier 0 zurück (deshalb habe ich nicht verwendet MorphologicalEulerNumber[]). Mma 9.01, Win XP.
Dr. Belisarius
Ich benutze auch 9.0.1, aber auf einem Mac. Wollen Sie damit sagen, dass Mathematica unter Windows eine andere Antwort als meine zurückgibt? Wenn ja, klingt das wie ein Fehler (in der Windows XP-Version).
DavidC
@ DavidCarraher Yep: i.stack.imgur.com/LKcr1.png
Dr. belisarius
@ Jan Dvorak. MorphologicalEulerNumbererfordert manchmal ein Bild; Es weigert sich, ein Grafikobjekt zu akzeptieren. In diesen Fällen sind die Größe des Lochs und die Auflösung kritisch (siehe codegolf.stackexchange.com/questions/8706/… ). Hier funktioniert es jedoch direkt mit dem Graphics-Objekt, das explizit alle Scheitelpunkte enthält. Ich stellte mir vor (oder hoffte), dass es einen Ansatz geben würde, der nicht vom Bild abhängt. Ich wünschte, ich wüsste, wie es versucht hat, das Problem zu lösen. Vielleicht klärt ein bisschen Höhlenforschung im Quellcode für die Funktion die Dinge.
DavidC
1

Python, 107

Mir wurde klar, dass das direkte Aufnehmen der Paare kürzer war als das from itertools import*Tippen combinations(). Ich bemerkte jedoch auch, dass meine Lösung auf den eingegebenen dreieckigen Flächen beruhte, deren Scheitelpunkte in konsistenter Reihenfolge aufgelistet waren. Daher sind die Zuwächse bei der Anzahl der Zeichen nicht so groß.

f=lambda l,t:1-len(l+t)+len(set([tuple(sorted(m))for n in[[i[:2],i[1:],[i[0],i[2]]]for i in t]for m in n]))

Python, 115

Eulers charakteristischer Ansatz, die Ausführlichkeit von itertools scheint unmöglich zu vermeiden. Ich frage mich, ob es billiger wäre, eine direktere Technik zum Erstellen von Scheitelpunktpaaren zu verwenden.

from itertools import*
f=lambda l,t:1-len(l+t)+len(set([m for n in[list(combinations(i,2)) for i in t]for m in n]))

Anwendungsbeispiel:

> f([[0,0],[1,0],[0,1],[1,2]],[[0,1,2],[1,2,3]])
> 0
> f([[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[.5,.5],[1.5,.5],[1.5,1.5],[.5,1.5]],[[5,6,11],[5,10,11],[4,5,10],[3,8,10],[2,3,9],[2,8,9],[1,2,8],[0,1,8],[0,8,11],[0,7,11],[6,7,11],[3,4,10]])
> 2
Kaya
quelle