Jumlah lubang dalam satu poligon

11

Masalahnya : Hitung jumlah lubang dalam poligon yang terhubung. Konektivitas poligon dijamin oleh kondisi bahwa setiap segitiga dalam triangulasi input berbagi setidaknya 1 sisi dengan segitiga lain dan bahwa hanya ada satu set segitiga yang terhubung.

Input adalah daftar Ldari npoin dalam pesawat dan daftar Tdari 3-tupel dengan masukan dari 0...n-1. Untuk setiap item dalam Ttupel (t_1,t_2,t_3)mewakili tiga simpul (dari daftar L) segitiga dalam triangulasi. Perhatikan bahwa ini adalah triangulasi dalam arti 'triangulasi poligon' , karena ini tidak akan pernah ada dua segitiga dalam Ttumpang tindih itu. Ketentuan tambahan adalah bahwa Anda tidak perlu membersihkan input, Ldan Ttidak mengandung pengulangan.

Contoh 1 : Jika L = {{0,0},{1,0},{0,1},{1,2}}dan T = {{0,1,2},{1,2,3}}kemudian poligon yang ditentukan memiliki jumlah lubang 0.

Gambar 1

Contoh 2 : Jika 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}}dan 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}}kemudian input poligon harus menghasilkan output 2.

Gambar 2

Tugasnya adalah menulis program terpendek (atau fungsi) yang mengambil Ldan Tsebagai input dan mengembalikan jumlah lubang. 'Pemenang' akan diakui sebagai entri dengan jumlah karakter paling sedikit (tanggal akhir tentatif 1 Juni).

Contoh pemformatan input (perhatikan 0 pengindeksan):

0,0
1,0
0,1
1,2
0,1,2
1,2,3    
Kaya
sumber
1
"Konektivitas poligon dijamin oleh kondisi bahwa setiap segitiga dalam triangulasi input berbagi setidaknya 1 sisi dengan segitiga lain." -- tidak. Itu bukan kondisi yang memadai. Ambil, misalnya T=1,2,3/1,2,4/5,6,7/5,6,8,. Setiap segitiga berbagi keunggulan dengan segitiga lain, tetapi triangulasi terputus
John Dvorak
Bolehkah kita menganggap input mewakili triangulasi parsial yang valid (tidak ada dua segitiga yang tumpang tindih dan tidak ada segitiga yang hadir dua kali) dan triangulasi terhubung?
John Dvorak
Bolehkah kita juga berasumsi bahwa input terhubung ke sisi dalam arti tidak mungkin untuk menghapus set poin yang terbatas untuk membuat bentuk terputus? (mis: T=1,2,3/1,4,5terhubung tetapi tidak terhubung ke tepi)
John Dvorak
2
Saya tidak yakin mengapa bisnis tentang tanggal akhir ini mulai muncul baru-baru ini. Anda diperbolehkan mengubah jawaban yang diterima, jadi tidak perlu menetapkan tanggal akhir. Masuk akal untuk memiliki ide mental bahwa Anda akan menunggu seminggu sebelum memilih jawaban agar tidak menakut-nakuti orang agar berpikir bahwa jawaban pertama tidak terkalahkan, tetapi selama Anda aktif di situs Anda dapat mengubah jawaban yang dipilih jika seseorang memposting yang lebih baik. Diskusi meta yang relevan termasuk meta.codegolf.stackexchange.com/q/542/194 dan meta.codegolf.stackexchange.com/q/193/194
Peter Taylor

Jawaban:

5

GolfScript (23 karakter)

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

Mengasumsikan format input menggunakan notasi larik GolfScript dan koordinat yang dikutip (atau tidak terpisahkan). Misalnya

$ 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

( Setara online )

atau

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

( Setara online )

Peter Taylor
sumber
5

Python, 71

Berikut ini adalah program (bukan fungsi ) yang menghitung angka yang diinginkan.

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

Contoh penggunaan:

>>> 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
Pasang kembali Monica
sumber
+1 untuk menggunakan gambar percikan, menggunakan frozenset alih-alih menyortir, zip (tidak bisa mengatakan saya pernah menggunakannya sebelumnya, perlu memperkenalkan diri.)
Kaya
3

APL, 36

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

Fungsi mengambil Lsebagai argumen kiri dan Tsebagai kanannya.

Sebagai contoh:

      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

Penjelasan, dari kanan ke kiri:

  • ⍴⍺,⍵menggabungkan dua vektor input dan mengembalikan panjangnya ( V + F)
  • Melangkah ke dalam blok berikutnya:
    • ¨⍵ menerapkan fungsi di sebelah kiri untuk setiap elemen argumen yang benar dan mengembalikan hasilnya
    • ⍵,⍵ mengembalikan argumen yang tepat digabungkan dengan dirinya sendiri
    • 3 2⍴membentuk argumen vektor menjadi tiga pasangan. Dalam hal ini pasangan dari item vektor pertama dan kedua, ketiga dan pertama, dan kedua dan ketiga.
    • ,/ bergabung dengan argumen vektor bersama
    • ⍵[⍋⍵] mengurutkan argumen yang benar
    • ∪/ memfilter duplikat apa pun
    • ⍴⊃ mengubah skalar bersarang menjadi vektor, dan mengembalikan panjangnya.
    • Seluruh fungsi mengembalikan jumlah tepi dalam bentuk ( E)
  • 1 cukup jelas (saya harap ...)

Seluruh fungsi lalu kembali 1+E-(V+F), atau 1-(F+V-E).

Keriangan
sumber
Persis seperti apa solusi GolfScript saya. Saya terkejut itu jauh lebih lama daripada GolfScript.
Peter Taylor
@PeterTaylor Saya terkejut solusi GolfScript Anda jauh lebih singkat! (Tapi sekali lagi, ini GolfScript)
Volatilitas
2

Mathematica, 93 (belum banyak bermain golf)

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

(Spaces ditambahkan untuk kejelasan)

Pengujian:

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
 *)
Belisarius
sumber
Bukankah ini bergantung pada segitiga atau lubang yang memiliki ukuran minimal tertentu (argumen untuk Erosion)?
John Dvorak
@ JanDvorak Mungkin saya salah, tapi saya pikir kecuali Anda menggunakan aritmatika presisi tak terbatas, solusi apa pun akan bekerja hingga Anda mencapai ukuran minimal tertentu (Anda harus memutuskan apakah tiga titik sejajar atau tidak). Hanya saja dalam solusi semacam ini masalahnya dinyatakan secara eksplisit.
Dr. belisarius
jika Anda menggunakan pendekatan topologi, Anda tidak harus melakukannya. Jika ada tiga titik collinear maka Anda memerlukan segitiga nol area di sana - jika tidak, Anda memiliki lubang.
John Dvorak
@belisarius. Inilah jawaban yang saya terima dari Dukungan Teknis Wolfram tentang perbedaan antara hasil kami: "Halo - Terima kasih atas email Anda. Saya telah mengkonfirmasi bahwa kode Anda memberikan hasil yang berbeda pada Mac dan Windows. Saya tidak berpikir bahwa ini adalah perilaku yang dimaksudkan, jadi Saya telah mengajukan laporan kepada pengembang kami tentang masalah ini. Saya pasti akan menyampaikan informasi bermanfaat yang saya dapatkan dari pengembang kami tentang masalah ini. Harap beri tahu saya jika Anda memiliki pertanyaan lebih lanjut ... Dukungan Teknis Wolfram Research , Inc. "
DavidC
@DavidCarraher "Ya, saya punya pertanyaan lebih lanjut: Apakah Anda akan mengirimkan saya cek untuk setiap bug?"
Dr. belisarius
2

Ruby, 239 karakter (227 tubuh)

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

perhatikan bahwa saya hanya mempertimbangkan topologi. Saya tidak menggunakan posisi titik dengan cara apa pun.

pemanggil (mengharapkan T dalam format Mathematica atau JSON):

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

Uji:

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
sumber
Yay, pendekatan karakteristik euler. Begitulah cara saya melakukannya dengan python.
Kaya
2
@Kaya. (Lihat Egg of Columbus en.wikipedia.org/wiki/Egg_of_Columbus ) Setelah seseorang memberikan jawaban Euler untuk pertanyaan Anda, kemungkinan orang lain akan mengikuti sangat meningkat. Saya dapat meyakinkan Anda bahwa jauh lebih menantang dan memuaskan untuk menemukan pendekatan sendiri, hanya setelah membuat koneksi ke pekerjaan Euler dengan polyhedra.
DavidC
2

Mathematica 76 73 72 67 62

Setelah banyak percobaan, saya menyadari bahwa lokasi yang tepat dari simpul tidak menjadi masalah, jadi saya merepresentasikan masalah dengan grafik. Invarian esensial, jumlah segitiga, tepi dan simpul tetap invarian (asalkan penyilangan garis dihindari).

Ada dua jenis "segitiga" internal dalam grafik: yang ada di sana mungkin adalah wajah, yaitu segitiga "terisi", dan yang tidak ada. Jumlah permukaan internal tidak memiliki hubungan dengan tepi atau simpul. Itu berarti bahwa menusuk lubang di grafik "penuh" hanya mengurangi jumlah wajah. Saya bermain secara sistematis dengan variasi di antara segitiga, melacak wajah, simpul dan tepi. Akhirnya saya menyadari bahwa jumlah lubang selalu sama dengan 1 - #faces - # vertices + #edges. Ini ternyata 1 minus karakteristik Euler (yang hanya saya ketahui tentang konteks polyhedra biasa (walaupun panjang tepinya jelas tidak penting).

Fungsi di bawah ini mengembalikan jumlah lubang ketika simpul dan segitiga dimasukkan. Tidak seperti pengiriman saya sebelumnya, itu tidak bergantung pada pemindaian gambar. Anda dapat menganggapnya sebagai 1 - Karakteristik Euler, yaitu 1 - (F + V -E) di mana F= #faces, V= # simpul, E= # tepi. Fungsi mengembalikan jumlah lubang 1 - (F + V -E),, mengingat wajah sebenarnya (segitiga) dan simpul.

Dapat dengan mudah diperlihatkan bahwa penghilangan segitiga apa pun di bagian luar kompleks tidak memengaruhi karakteristik Euler, terlepas dari apakah segitiga itu berbagi satu atau dua sisi dengan segitiga lainnya.

Catatan: Huruf kecil vakan digunakan sebagai pengganti dari Lformulasi asli; yaitu, berisi simpul itu sendiri (bukan V, jumlah simpul)

fdigunakan untuk Tdari formulasi asli; yaitu, berisi segitiga, direpresentasikan sebagai triple dipesan dari indeks titik.

Kode

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

(Terima kasih kepada Tn. Wizard untuk mencukur 5 karakter dengan menghilangkan aturan penggantian.)


Contoh 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

Nol lubang.


Contoh 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

Jadi, 2 lubang dalam contoh 2.

DavidC
sumber
apakah Anda pada dasarnya merasterisasi triangulasi dan membuang perpustakaan grafis pada gambar itu? Bukankah itu gagal jika lubangnya terlalu kecil?
John Dvorak
1
contoh kedua Anda mengembalikan 0 di sini (itu sebabnya saya belum pernah menggunakan MorphologicalEulerNumber[]). Mma 9.01, Menangkan XP.
Dr. belisarius
Saya menggunakan 9.0.1 juga, tetapi pada Mac. Apakah Anda mengatakan Mathematica mengembalikan jawaban yang berbeda dari saya di Windows? Jika demikian, itu terdengar seperti bug (dalam versi Windows XP).
DavidC
@DavidCarraher Yap: i.stack.imgur.com/LKcr1.png
Dr. belisarius
@ Jan Dvorak. MorphologicalEulerNumberterkadang membutuhkan gambar; ia menolak untuk menerima objek grafis. Dalam kasus ini, ukuran lubang dan resolusi sangat penting (lihat codegolf.stackexchange.com/questions/8706/… ). Tapi di sini ia bekerja secara langsung dengan objek Grafik, yang secara eksplisit berisi semua simpul. Saya membayangkan (atau berharap) bahwa itu akan menggunakan pendekatan yang tidak bergantung pada gambar. Saya berharap saya tahu bagaimana upaya untuk memecahkan masalah ini. Mungkin beberapa spelunking dalam kode sumber untuk fungsi ini akan mengklarifikasi hal-hal.
DavidC
1

Python, 107

Saya menyadari bahwa mengambil pasangan secara langsung lebih pendek daripada from itertools import*dan mengetik combinations(). Namun saya juga memperhatikan bahwa solusi saya bergantung pada wajah segitiga input dengan simpulnya terdaftar dalam urutan yang konsisten. Oleh karena itu keuntungan dalam jumlah karakter tidak terlalu besar.

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

Dengan pendekatan karakteristik Euler, verbositas itertools tampaknya mustahil untuk dihindari. Saya ingin tahu apakah akan lebih murah menggunakan teknik yang lebih langsung untuk membuat pasangan simpul.

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

Contoh penggunaan:

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