Nombre de trous dans un polygone

11

Le problème : comptez le nombre de trous dans un polygone connecté. La connectivité du polygone est garantie par la condition que chaque triangle de la triangulation d'entrée partage au moins 1 côté avec un autre triangle et qu'il n'y ait qu'un seul ensemble de triangles connectés.

L'entrée est une liste Lde npoints dans le plan et une liste Tde 3 tuples avec des entrées de 0...n-1. Pour chaque élément Tdu tuple (t_1,t_2,t_3)représente les trois sommets (de la liste L) d'un triangle dans la triangulation. Notez qu'il s'agit d'une triangulation au sens de «triangulation polygonale» , car il n'y aura jamais deux triangles dans Tce chevauchement. Une stipulation supplémentaire est que vous n'aurez pas à assainir l'entrée Let à Tne pas contenir de répétitions.

Exemple 1 : Si L = {{0,0},{1,0},{0,1},{1,2}}et T = {{0,1,2},{1,2,3}}alors le polygone spécifié a un nombre de trous de 0.

Figure 1

Exemple 2 : Si 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}}et 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}}alors l'entrée polygonale devrait donner une sortie de 2.

Figure 2

La tâche consiste à écrire le programme (ou la fonction) le plus court qui prend Let Tcomme entrée et renvoie le nombre de trous. Le «gagnant» sera reconnu comme l'entrée avec le moins de caractères (date de fin provisoire le 1er juin).

Exemple de formatage d'entrée (notez l'indexation 0):

0,0
1,0
0,1
1,2
0,1,2
1,2,3    
Kaya
la source
1
"La connectivité du polygone est garantie par la condition que chaque triangle de la triangulation d'entrée partage au moins 1 côté avec un autre triangle." -- non. Ce n'est pas une condition suffisante. Prenez, par exemple T=1,2,3/1,2,4/5,6,7/5,6,8,. Chaque triangle partage un bord avec un autre triangle, mais la triangulation est déconnectée
John Dvorak
Pouvons-nous supposer que l'entrée représente une triangulation partielle valide (aucun triangle ne se chevauche et aucun triangle n'est présent deux fois) et la triangulation est connectée?
John Dvorak
Pouvons-nous également supposer que l'entrée est connectée aux bords dans le sens où il n'est pas possible de supprimer un ensemble fini de points pour rendre la forme déconnectée? (ex: T=1,2,3/1,4,5est connecté mais pas connecté en périphérie)
John Dvorak
2
Je ne sais pas pourquoi cette entreprise sur les dates de fin a commencé à apparaître récemment. Vous êtes autorisé à modifier la réponse acceptée, il n'est donc pas nécessaire de définir une date de fin. Il est raisonnable d'avoir une idée mentale que vous attendez une semaine avant de sélectionner une réponse afin de ne pas effrayer les gens en leur faisant croire que la première réponse est imbattable, mais tant que vous êtes actif sur le site, vous pouvez modifier la réponse sélectionnée si quelqu'un en publie un meilleur. Les méta-discussions pertinentes incluent meta.codegolf.stackexchange.com/q/542/194 et meta.codegolf.stackexchange.com/q/193/194
Peter Taylor

Réponses:

5

GolfScript (23 caractères)

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

Suppose le format d'entrée à l'aide de la notation de tableau GolfScript et des coordonnées entre guillemets (ou intégrales). Par exemple

$ 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

( Équivalent en ligne )

ou

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

( Équivalent en ligne )

Peter Taylor
la source
5

Python, 71

Ce qui suit est un programme (pas une fonction ) qui calcule le nombre souhaité.

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

Exemple d'utilisation:

>>> 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
Réintégrer Monica
la source
+1 pour utiliser le splat, en utilisant frozenset au lieu de trier, zip (ne peut pas dire que je l'ai déjà utilisé auparavant, je dois me familiariser.)
Kaya
3

APL, 36

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

La fonction prend Lcomme argument de gauche et Tcomme droite.

Par exemple:

      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

Explication, allant de droite à gauche:

  • ⍴⍺,⍵concatène les deux vecteurs d'entrée et renvoie leur longueur ( V + F)
  • Entrer dans le bloc suivant:
    • ¨⍵ applique la fonction de gauche à chaque élément de l'argument de droite et renvoie le résultat
    • ⍵,⍵ renvoie le bon argument concaténé avec lui-même
    • 3 2⍴façonne l'argument vecteur en trois paires. Dans ce cas, il associe les premier et deuxième, troisième et premier, et deuxième et troisième éléments du vecteur.
    • ,/ joint l'argument vecteur ensemble
    • ⍵[⍋⍵] trie le bon argument
    • ∪/ filtre tous les doublons
    • ⍴⊃ transforme un scalaire imbriqué en vecteur et en renvoie la longueur.
    • La fonction entière renvoie le nombre d'arêtes dans la forme ( E)
  • 1 est explicite (j'espère ...)

La fonction entière retourne alors 1+E-(V+F), ou 1-(F+V-E).

Volatilité
la source
À peu près exactement ce que fait ma solution GolfScript. Je suis surpris que ce soit beaucoup plus long que GolfScript.
Peter Taylor
@PeterTaylor J'ai été surpris que votre solution GolfScript soit tellement plus courte! (Mais là encore, il est GolfScript)
Volatilité
2

Mathematica, 93 (pas encore beaucoup joué au golf)

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

(Espaces ajoutés pour plus de clarté)

Essai:

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
la source
Cela ne repose-t-il pas sur des triangles ou des trous ayant une certaine taille minimale (l'argument de Erosion)?
John Dvorak
@JanDvorak Je me trompe peut-être, mais je pense que si vous n'utilisez pas l'arithmétique de précision infinie, toute solution fonctionnera jusqu'à ce que vous atteigniez une certaine taille minimale (vous devrez décider si trois points sont alignés ou non). C'est juste que dans ce type de solution, le problème est explicitement énoncé.
Dr belisarius
si vous utilisez l'approche topologique, vous n'êtes pas obligé. S'il y a trois points colinéaires, vous avez besoin d'un triangle de zone nulle - sinon vous avez un trou.
John Dvorak
@belisarius. Voici la réponse que j'ai reçue du support technique de Wolfram à propos de l'écart entre nos résultats: "Bonjour - Merci pour votre e-mail. J'ai confirmé que votre code donne des résultats différents sur Mac et Windows. Je ne pense pas que ce soit un comportement voulu, donc J'ai déposé un rapport auprès de nos développeurs sur le problème. Je serai sûr de transmettre toute information utile que j'obtiendrai de nos développeurs à ce sujet. Veuillez me faire savoir si vous avez d'autres questions. ... Support technique Wolfram Research , Inc. "
DavidC
@DavidCarraher "Oui, j'ai d'autres questions: m'enverrez-vous un chèque pour chaque bug?"
Dr belisarius
2

Ruby, 239 caractères (227 corps)

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

notez que je ne considère que la topologie. Je n'utilise en aucune façon les positions des sommets.

appelant (attend T au format Mathematica ou JSON):

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

Tester:

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
la source
Oui, une approche caractéristique d'Euler. C'est comme ça que je l'ai fait en python.
Kaya
2
@Kaya. (Voir Egg of Columbus en.wikipedia.org/wiki/Egg_of_Columbus ) Une fois que quelqu'un a donné une réponse eulérienne à votre question, la probabilité que d'autres le suivent augmente considérablement. Je peux vous assurer qu'il est beaucoup plus difficile et gratifiant de découvrir l'approche par soi-même, pour ensuite faire le lien avec le travail d'Euler avec les polyèdres.
DavidC
2

Mathematica 76 73 72 67 62

Après beaucoup d'expérimentation, j'ai réalisé que l'emplacement précis des sommets n'était pas un problème, j'ai donc représenté le problème avec les graphiques. Les invariants essentiels, le nombre de triangles, d'arêtes et de sommets sont restés invariants (à condition d'éviter le croisement de lignes).

Il y avait deux types de "triangles" internes dans le graphique: ceux qui étaient là étaient vraisemblablement un visage, c'est-à-dire un triangle "rempli", et ceux où il n'y en avait pas. Le nombre de faces internes n'avait aucune relation avec les arêtes ou les sommets. Cela signifiait que creuser des trous dans des graphiques entièrement "remplis" ne réduisait que le nombre de faces. J'ai joué systématiquement avec des variations entre les triangles, en gardant une trace des faces, des sommets et des bords. Finalement, j'ai réalisé que le nombre de trous était toujours égal à 1 - #faces - # vertices + #edges. Cela s'est avéré être 1 moins la caractéristique d'Euler (que je ne connaissais que dans le contexte des polyèdres réguliers (bien que la longueur des bords n'ait clairement aucune importance).

La fonction ci-dessous renvoie le nombre de trous lorsque les sommets et triangles sont entrés. Contrairement à ma soumission précédente, elle ne repose pas sur la numérisation d'une image. Vous pouvez le considérer comme 1 - la caractéristique d'Euler, c'est-à-dire 1 - (F + V -E) où F= #faces, V= # sommets, E= # bords. La fonction renvoie le nombre de trous, 1 - (F + V -E)étant donné les faces réelles (triangles) et les sommets.

On peut facilement montrer que la suppression de tout triangle à l'extérieur du complexe n'a aucun effet sur la caractéristique d'Euler, qu'il partage un ou deux côtés avec d'autres triangles.

Remarque: les minuscules vseront utilisées à la place de celles Lde la formulation d'origine; c'est-à-dire qu'il contient les sommets eux-mêmes (pas V, le nombre de sommets)

fest utilisé pour la Tformule originale; c'est-à-dire qu'il contient les triangles, représentés comme le triple ordonné des indices de vertex.

Code

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

(Merci à M. Wizard d'avoir rasé 5 caractères en éliminant la règle de remplacement.)


Exemple 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

Zéro trou.


Exemple 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

Ainsi, 2 trous sont dans l'exemple 2.

DavidC
la source
êtes-vous en train de tramer la triangulation et de vider une bibliothèque graphique sur cette image? Cela ne marche-t-il pas si un trou est trop petit?
John Dvorak
1
votre deuxième exemple renvoie 0 ici (c'est pourquoi je ne l'ai pas utilisé MorphologicalEulerNumber[]). Mma 9.01, Win XP.
Dr belisarius
J'utilise aussi 9.0.1, mais sur un Mac. Voulez-vous dire que Mathematica renvoie une réponse différente de la mienne sous Windows? Si c'est le cas, cela ressemble à un bogue (dans la version Windows XP).
DavidC
@DavidCarraher Yep: i.stack.imgur.com/LKcr1.png
Dr belisarius
@Jan Dvorak. MorphologicalEulerNumbernécessite parfois une image; il refuse d'accepter un objet graphique. Dans ces cas, la taille du trou et la résolution sont critiques (voir codegolf.stackexchange.com/questions/8706/… ). Mais ici, il fonctionne directement avec l'objet Graphics, qui contient explicitement tous les sommets. J'ai imaginé (ou espéré) qu'il utiliserait une approche qui ne dépendrait pas de l'image. Je souhaite savoir comment il a tenté de résoudre le problème. Peut-être qu'un peu de spéléologie dans le code source de la fonction clarifiera les choses.
DavidC
1

Python, 107

J'ai réalisé que prendre les paires directement était plus court que from itertools import*et taper combinations(). Pourtant, j'ai également remarqué que ma solution reposait sur les faces triangulaires d'entrée dont les sommets étaient répertoriés dans un ordre cohérent. Par conséquent, les gains en nombre de caractères ne sont pas si importants.

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

Approche caractéristique d'Euler, la verbosité des outils semble impossible à éviter. Je me demande s'il serait moins cher d'utiliser une technique plus directe pour faire des paires de sommets.

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]))

Exemple d'utilisation:

> 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
la source