Numero di fori in un poligono


11

Il problema : contare il numero di fori in un poligono collegato. La connettività del poligono è garantita dalla condizione che ogni triangolo nella triangolazione di input condivida almeno 1 lato con un altro triangolo e che vi sia solo un tale insieme di triangoli collegati.

Input è un elenco Ldi npunti nel piano e un elenco Tdi 3 tuple con voci da 0...n-1. Per ogni elemento nella Ttupla (t_1,t_2,t_3)rappresenta i tre vertici (dall'elenco L) di un triangolo nella triangolazione. Si noti che questa è una triangolazione nel senso di "triangolazione poligonale" , per questo motivo non ci saranno mai due triangoli in Tquella sovrapposizione. Una clausola aggiuntiva è che non dovrai disinfettare l'input Le Tnon contenere alcuna ripetizione.

Esempio 1 : Se L = {{0,0},{1,0},{0,1},{1,2}}e T = {{0,1,2},{1,2,3}}quindi il poligono specificato ha un conteggio dei fori pari a 0.

Figura 1

Esempio 2 : se 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}}e 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}}quindi l'input poligonale dovrebbe generare un output di 2.

figura 2

Il compito è scrivere il programma (o la funzione) più breve che accetta Le Tcome input e restituisce il numero di buche. Il "vincitore" verrà riconosciuto come l'ingresso con il minor numero di caratteri (data di fine provvisoria 1 giugno).

Formattazione di input di esempio (notare l'indicizzazione 0):

0,0
1,0
0,1
1,2
0,1,2
1,2,3    

1
"La connettività del poligono è garantita dalla condizione che ogni triangolo nella triangolazione di input condivida almeno 1 lato con un altro triangolo." -- no. Questa non è una condizione sufficiente. Prendi, per esempio T=1,2,3/1,2,4/5,6,7/5,6,8,. Ogni triangolo condivide un bordo con un altro triangolo, ma la triangolazione è disconnessa
John Dvorak,

Possiamo supporre che l'input rappresenti una triangolazione parziale valida (non si sovrappongono due triangoli e nessun triangolo è presente due volte) e la triangolazione è connessa?
John Dvorak,


Possiamo anche supporre che l'ingresso sia collegato ai bordi, nel senso che non è possibile rimuovere un insieme finito di punti per rendere scollegata la forma? (es: T=1,2,3/1,4,5è connesso ma non connesso)
John Dvorak,

2
Non sono sicuro del perché questa attività sulle date di fine sia iniziata di recente. Puoi modificare la risposta accettata, quindi non è necessario impostare una data di fine. È ragionevole avere un'idea mentale che aspetterai una settimana prima di selezionare una risposta per non spaventare le persone nel pensare che la prima risposta è imbattibile, ma finché sei attivo sul sito puoi cambiare la risposta selezionata se qualcuno ne pubblica uno migliore. Le meta-discussioni pertinenti includono meta.codegolf.stackexchange.com/q/542/194 e meta.codegolf.stackexchange.com/q/193/194
Peter Taylor,

Risposte:


5

GolfScript (23 caratteri)

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

Presuppone il formato di input utilizzando la notazione dell'array GolfScript e le coordinate quotate (o integrali). Per esempio

$ 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

( Equivalente online )

o

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

( Equivalente online )


5

Python, 71

Quello che segue è un programma (non una funzione ) che calcola il numero desiderato.

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

Esempio di utilizzo:

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

+1 per usare lo splat, usando frozenset invece di ordinare, zip (non posso dire che non l'ho mai usato prima, ho bisogno di conoscermi).
Kaya

3

APL, 36

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

La funzione assume Lcome argomento sinistro e Tcome diritto.

Per esempio:

      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

Spiegazione, da destra a sinistra:

  • ⍴⍺,⍵concatena i due vettori di input e restituisce la loro lunghezza ( V + F)
  • Entrare nel blocco successivo:
    • ¨⍵ applica la funzione a sinistra a ogni elemento dell'argomento destro e restituisce il risultato
    • ⍵,⍵ restituisce l'argomento giusto concatenato con se stesso
    • 3 2⍴modella l'argomento vettoriale in tre coppie. In questo caso accoppia il primo e il secondo, il terzo e il primo e il secondo e il terzo elemento del vettore.
    • ,/ unisce l'argomento vettoriale
    • ⍵[⍋⍵] ordina l'argomento giusto
    • ∪/ filtra eventuali duplicati
    • ⍴⊃ trasforma uno scalare nidificato in un vettore e ne restituisce la lunghezza.
    • L'intera funzione restituisce il numero di spigoli nella forma ( E)
  • 1 è autoesplicativo (spero ...)

L'intera funzione quindi ritorna 1+E-(V+F), o 1-(F+V-E).


Praticamente esattamente ciò che fa la mia soluzione GolfScript. Sono sorpreso che sia molto più lungo di GolfScript.
Peter Taylor,

@PeterTaylor Sono stato sorpreso che la tua soluzione GolfScript sia stata molto più breve! (Ma poi di nuovo, è GolfScript)
Volatilità

2

Mathematica, 93 (non ancora giocato a golf)

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

(Spazi aggiunti per maggiore chiarezza)

test:

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

Non si basa sul fatto che triangoli o buchi abbiano determinate dimensioni minime (l'argomento per Erosion)?
John Dvorak,

@JanDvorak Forse mi sbaglio, ma penso che se non usi l'aritmetica di precisione infinita, qualsiasi soluzione funzionerà fino a raggiungere una certa dimensione minima (dovrai decidere se tre punti sono allineati o meno). È solo che in questo tipo di soluzione il problema è esplicitamente dichiarato.
Dr. belisarius,

se usi l'approccio topologico, non è necessario. Se ci sono tre punti collineari, allora hai bisogno di un triangolo ad area zero lì, altrimenti hai un buco.
John Dvorak,

@belisarius. Ecco la risposta che ho ricevuto dal supporto tecnico Wolfram riguardo alla discrepanza tra i nostri risultati: "Ciao - Grazie per la tua email. Ho confermato che il tuo codice fornisce risultati diversi su Mac e Windows. Non penso che si tratti di un comportamento previsto, quindi Ho presentato un rapporto con i nostri sviluppatori sul problema. Sarò sicuro di trasmettere qualsiasi informazione utile che ottengo dai nostri sviluppatori su questo problema. Per favore fatemi sapere se avete ulteriori domande ... Supporto tecnico Wolfram Research , Inc. "
DavidC,

@DavidCarraher "Sì, ho ulteriori domande: mi manderai un assegno per ogni errore?"
Dr. belisarius,

2

Rubino, 239 caratteri (227 corpi)

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

nota che sto solo considerando la topologia. Non sto usando le posizioni dei vertici in alcun modo.

chiamante (si aspetta T in formato Mathematica o JSON):

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

Test:

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

Sì, un approccio caratteristico eulero. È così che l'ho fatto in Python.
Kaya,

2
@Kaya. (Vedi Egg of Columbus en.wikipedia.org/wiki/Egg_of_Columbus ) Una volta che qualcuno ha dato una risposta euleriana alla tua domanda, la probabilità che altri seguano aumenta notevolmente. Posso assicurarti che è molto più stimolante e gratificante scoprire l'approccio da soli, solo dopo aver fatto il collegamento al lavoro di Eulero con i poliedri.
DavidC,

2

Mathematica 76 73 72 67 62

Dopo molte sperimentazioni, mi sono reso conto che la posizione precisa dei vertici non era preoccupante, quindi ho rappresentato il problema con i grafici. Gli invarianti essenziali, il numero di triangoli, bordi e vertici rimasero invarianti (purché si evitasse l'attraversamento di linee).

C'erano due tipi di "triangoli" interni nel grafico: quelli erano presumibilmente una faccia, cioè un triangolo "pieno", e quelli dove non c'erano. Il numero di facce interne non aveva alcuna relazione con i bordi o i vertici. Ciò significava che fare buchi nei grafici completamente "riempiti" riduceva solo il numero di facce. Ho giocato sistematicamente con variazioni tra i triangoli, tenendo traccia di facce, vertici e bordi. Alla fine mi sono reso conto che il numero di fori era sempre uguale a 1 - # facce - # vertici + # bordi. Ciò si è rivelato essere 1 meno la caratteristica di Eulero (che avevo conosciuto solo nel contesto dei poliedri regolari (sebbene la lunghezza dei bordi non avesse chiaramente alcuna importanza).

La funzione seguente restituisce il numero di fori quando vengono immessi vertici e triangoli. A differenza della mia precedente presentazione, non si basa su una scansione di un'immagine. Puoi pensarlo come 1 - Caratteristica di Eulero, ovvero 1 - (F + V-E) dove F= #facce, V= # vertici, E= # spigoli. La funzione restituisce il numero di fori, 1 - (F + V -E)date le facce (triangoli) e i vertici effettivi.

Si può facilmente dimostrare che la rimozione di qualsiasi triangolo all'esterno del complesso non ha alcun effetto sulla caratteristica di Eulero, indipendentemente dal fatto che condivida uno o 2 lati con altri triangoli.

Nota: la minuscola vverrà utilizzata al posto della Lformulazione originale; cioè contiene i vertici stessi (non V, il numero di vertici)

fè usato per la Tformulazione originale; cioè contiene i triangoli, rappresentati come il triplo ordinato degli indici dei vertici.

Codice

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

(Grazie a Mr. Wizard per aver rasato 5 caratteri eliminando la regola di sostituzione.)


Esempio 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

Zero fori.


Esempio 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

Pertanto, 2 fori sono nell'esempio 2.


stai fondamentalmente rasterizzando la triangolazione e scaricando una libreria grafica su quell'immagine? Non fallisce se un buco è troppo piccolo?
John Dvorak,

1
il tuo secondo esempio restituisce 0 qui (ecco perché non l'ho usato MorphologicalEulerNumber[]). Mma 9.01, vinci XP.
Dr. belisarius,

Sto usando anche 9.0.1, ma su un Mac. Stai dicendo che Mathematica restituisce una risposta diversa dalla mia su Windows? In tal caso, sembra un bug (nella versione di Windows XP).
DavidC,


@Jan Dvorak. MorphologicalEulerNumbera volte richiede un'immagine; rifiuta di accettare un oggetto grafico. In questi casi, la dimensione del foro e la risoluzione sono fondamentali (vedi codegolf.stackexchange.com/questions/8706/… ). Ma qui funziona direttamente con l'oggetto Graphics, che contiene esplicitamente tutti i vertici. Ho immaginato (o sperato) che avrebbe usato un approccio che non dipendeva dall'immagine. Vorrei sapere come ha tentato di risolvere il problema. Forse qualche spelunking nel codice sorgente per la funzione chiarirà le cose.
DavidC,

1

Python, 107

Mi sono reso conto che prendere le coppie direttamente era più corto di from itertools import* e digitando combinations(). Tuttavia ho anche notato che la mia soluzione si basava sulle facce triangolari di input con i loro vertici elencati in ordine coerente. Pertanto i guadagni nel conteggio dei personaggi non sono così grandi.

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

Approccio caratteristico di Eulero, la verbosità degli itertools sembra impossibile da evitare. Mi chiedo se sarebbe più economico usare una tecnica più diretta per fare coppie di vertici.

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

Esempio di utilizzo:

> 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.