Número de furos em um polígono


11

O problema : conte o número de furos em um polígono conectado. A conectividade do polígono é garantida pela condição de que cada triângulo na triangulação de entrada compartilhe pelo menos um lado com outro triângulo e que exista apenas um desses conjuntos de triângulos conectados.

Entrada é uma lista Lde npontos no plano e uma lista Tde três tuplas com entradas de 0...n-1. Para cada item Tda tupla (t_1,t_2,t_3)representa os três vértices (da lista L) de um triângulo na triangulação. Observe que essa é uma triangulação no sentido de 'triangulação de polígono' , por isso nunca haverá dois triângulos Tnessa sobreposição. Uma estipulação adicional é que você não precisará higienizar a entrada Le Tnão contém repetições.

Exemplo 1 : se L = {{0,0},{1,0},{0,1},{1,2}}e, em T = {{0,1,2},{1,2,3}}seguida, o polígono especificado tem uma contagem de orifícios de 0.

figura 1

Exemplo 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, em 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}}seguida, a entrada do polígono deve resultar em uma saída 2.

Figura 2

A tarefa é escrever o programa (ou função) mais curto que recebe Le Tcomo entrada e retorna o número de furos. O 'vencedor' será reconhecido como a entrada com o menor número de caracteres (data final prevista para 1º de junho).

Exemplo de formatação de entrada (observe a indexação 0):

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

1
"A conectividade do polígono é garantida pela condição de que cada triângulo na triangulação de entrada compartilhe pelo menos um lado com outro triângulo." -- não. Essa não é uma condição suficiente. Tome, por exemplo T=1,2,3/1,2,4/5,6,7/5,6,8,. Cada triângulo compartilha uma borda com outro triângulo, mas a triangulação está desconectada
John Dvorak

Podemos assumir que a entrada representa uma triangulação parcial válida (não há dois triângulos sobrepostos e nenhum triângulo está presente duas vezes) e a triangulação está conectada?
John Dvorak


Podemos também assumir que a entrada está conectada por arestas no sentido de que não é possível remover um conjunto finito de pontos para tornar a forma desconectada? (ex: T=1,2,3/1,4,5está ligado, mas não edge-conectado)
John Dvorak

2
Não sei por que esse negócio sobre datas de término começou a surgir recentemente. Você tem permissão para alterar a resposta aceita, portanto, não é necessário definir uma data de término. É razoável ter uma idéia mental de que você esperará uma semana antes de selecionar uma resposta para não assustar as pessoas a pensarem que a primeira resposta é imbatível, mas enquanto você estiver ativo no site, poderá alterar a resposta selecionada se alguém postar uma melhor. As meta-discussões relevantes incluem meta.codegolf.stackexchange.com/q/542/194 e meta.codegolf.stackexchange.com/q/193/194
Peter Taylor

Respostas:


5

GolfScript (23 caracteres)

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

Assume o formato de entrada usando a notação de matriz GolfScript e as coordenadas entre aspas (ou integrais). Por exemplo

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

ou

$ 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

O que se segue é um programa (não uma função ) que calcula o número desejado.

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

Exemplo de uso:

>>> 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 para usar o splat, usando frozenset vez de triagem, zip (não posso dizer que já usei isso antes, necessidade de me familiarizar.)
Kaya

3

APL, 36

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

A função assume Lcomo argumento à esquerda e Tà direita.

Por exemplo:

      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

Explicação, indo da direita para a esquerda:

  • ⍴⍺,⍵concatena os dois vetores de entrada e retorna seu comprimento ( V + F)
  • Entrando no próximo bloco:
    • ¨⍵ aplica a função à esquerda a todos os elementos do argumento certo e retorna o resultado
    • ⍵,⍵ retorna o argumento correto concatenado consigo mesmo
    • 3 2⍴molda o argumento do vetor em três pares. Nesse caso, ele une o primeiro e o segundo, o terceiro e o primeiro e o segundo e o terceiro itens do vetor.
    • ,/ une o argumento do vetor
    • ⍵[⍋⍵] classifica o argumento certo
    • ∪/ filtra quaisquer duplicatas
    • ⍴⊃ transforma um escalar aninhado em um vetor e retorna o comprimento dele.
    • A função inteira retorna o número de arestas na forma ( E)
  • 1 é auto-explicativo (espero ...)

A função inteira retorna 1+E-(V+F), ou 1-(F+V-E).


Praticamente exatamente o que minha solução GolfScript faz. Estou surpreso que seja muito mais longo que o GolfScript.
22613 Peter Taylor

@ PeterTaylor Fiquei surpreso que sua solução GolfScript fosse muito mais curta! (Mas, novamente, isso é GolfScript)
Volatilidade

2

Mathematica, 93 (ainda não jogou muito golfe)

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

(Espaços adicionados para maior clareza)

Teste:

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

Isso não depende de triângulos ou furos com certo tamanho mínimo (o argumento para Erosion)?
John Dvorak

@JanDvorak Talvez eu esteja errado, mas acho que, a menos que você use aritmética de precisão infinita, qualquer solução funcionará até você atingir um determinado tamanho mínimo (você terá que decidir se três pontos estão alinhados ou não). É que, nesse tipo de solução, o problema é explicitamente declarado.
Dr. belisarius

se você usar a abordagem topológica, não precisará. Se houver três pontos colineares, você precisará de um triângulo de área zero - caso contrário, você terá um furo.
John Dvorak

@belisarius. Aqui está a resposta que recebi do Suporte Técnico da Wolfram sobre a discrepância entre nossos resultados: "Olá - Obrigado por seu e-mail. Confirmei que seu código fornece resultados diferentes no Mac e no Windows. Não acho que esse seja o comportamento pretendido. Arquivei um relatório com nossos desenvolvedores sobre o problema. Certifico-me de passar todas as informações úteis que recebo de nossos desenvolvedores sobre esse problema. Informe-me se tiver mais alguma dúvida ... Suporte Técnico Wolfram Research , Inc. "
DavidC

@DavidCarraher "Sim, tenho mais perguntas: você me envia um cheque para cada bug?"
Dr. belisarius

2

Ruby, 239 caracteres (227 corpo)

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

observe que estou considerando apenas a topologia. Eu não estou usando as posições de vértice de forma alguma.

chamador (espera T no formato Mathematica ou JSON):

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

Teste:

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

Yay, uma abordagem característica de Euler. Foi assim que fiz em python.
Kaya

2
@Kaya. (Veja Ovo de Colombo en.wikipedia.org/wiki/Egg_of_Columbus ) Quando alguém dá uma resposta euleriana à sua pergunta, a probabilidade de outras pessoas seguirem aumenta muito. Posso garantir que é muito mais desafiador e gratificante descobrir a abordagem por conta própria, só depois estabelecendo a conexão com o trabalho de Euler com os poliedros.
21313 DavidC

2

Mathematica 76 73 72 67 62

Após muita experimentação, percebi que a localização precisa dos vértices não era preocupante, então representei o problema com os gráficos. Os invariantes essenciais, o número de triângulos, arestas e vértices permaneceram invariáveis ​​(desde que a passagem de linha fosse evitada).

Havia dois tipos de "triângulos" internos no gráfico: esses eram presumivelmente uma face, isto é, um triângulo "cheio" e aqueles onde não havia. O número de faces internas não teve nenhuma relação com as arestas ou vértices. Isso significava que fazer furos em gráficos totalmente "preenchidos" reduzia apenas o número de faces. Joguei sistematicamente com variações entre triângulos, acompanhando os rostos, vértices e arestas. Eventualmente, percebi que o número de furos sempre era igual a 1 - #faces - # vértices + #edges. Isso acabou por ser 1 menos a característica de Euler (que eu só conhecia no contexto dos poliedros regulares (embora o comprimento das bordas não tenha claramente nenhuma importância).

A função abaixo retorna o número de furos quando os vértices e triângulos são inseridos. Ao contrário do meu envio anterior, ele não depende da digitalização de uma imagem. Você pode pensar nisso como 1 - característica de Euler, ou seja, 1 - (F + V-E) onde F= #faces, V= # vértices, E= # arestas. A função retorna o número de furos, 1 - (F + V -E)considerando as faces reais (triângulos) e vértices.

Pode-se mostrar facilmente que a remoção de qualquer triângulo na parte externa do complexo não afeta a característica de Euler, independentemente de compartilhar um ou dois lados com outros triângulos.

Nota: A minúscula vserá usada no lugar da Lformulação original; isto é, contém os próprios vértices (não V, o número de vértices)

fé usado para a Tpartir da formulação original; isto é, contém os triângulos, representados como o triplo ordenado dos índices de vértices.

Código

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

(Agradecemos ao Sr. Wizard por cortar 5 caracteres ao eliminar a regra de substituição.)


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

Zero orifícios.


Exemplo 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

Assim, 2 furos estão no exemplo 2.


você está basicamente rasterizando a triangulação e despejando uma biblioteca de gráficos nessa imagem? Isso não falha se um buraco é muito pequeno?
John Dvorak

1
seu segundo exemplo retorna 0 aqui (é por isso que não usei MorphologicalEulerNumber[]). Mma 9.01, Win XP.
Dr. belisarius

Também estou usando a 9.0.1, mas em um Mac. Você está dizendo que o Mathematica retorna uma resposta diferente da minha no Windows? Nesse caso, isso soa como um bug (na versão do Windows XP).
DavidC


@Jan Dvorak. MorphologicalEulerNumberàs vezes requer uma imagem; ele se recusa a aceitar um objeto gráfico. Nesses casos, o tamanho do furo e a resolução são críticos (consulte codegolf.stackexchange.com/questions/8706/… ). Mas aqui ele trabalha diretamente com o objeto Graphics, que contém explicitamente todos os vértices. Imaginei (ou esperava) que usasse uma abordagem que não dependesse da imagem. Eu gostaria de saber como ele tentou resolver o problema. Talvez alguma spelunking no código fonte da função esclareça as coisas.
DavidC

1

Python, 107

Percebi que pegar os pares diretamente era mais curto from itertools import*e digitar combinations(). No entanto, também notei que minha solução contava com as faces triangulares de entrada com seus vértices listados em ordem consistente. Portanto, os ganhos na contagem de caracteres não são tão grandes.

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

Abordagem característica de Euler, a verbosidade dos instrumentos de controle parece impossível de evitar. Gostaria de saber se seria mais barato usar uma técnica mais direta para fazer pares de vértices.

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

Exemplo de uso:

> 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.