Hitung jumlah sisi pada poligon

18

Hitung jumlah sisi pada poligon

Robot penghitung sisi poligon telah memutuskan untuk melakukan perjalanan dunia tanpa memberitahu siapa pun sebelumnya, tetapi sangat penting bahwa proses penghitungan poligon tidak dihentikan terlalu lama. Jadi, Anda memiliki tugas berikut: Diberikan gambar hitam dan putih poligon, program / functoin Anda harus mengembalikan jumlah sisi.

Program ini akan diumpankan ke komputer kartu punch lama, dan karena kartu punch sangat mahal saat ini, Anda sebaiknya mencoba membuat program Anda sesingkat mungkin.

Tepi setidaknya 10 piksel, dan sudut yang dibentuk oleh dua tepi adjecent setidaknya 10 ° tetapi tidak lebih dari 170 ° (atau lebih besar dari 190 °). Poligon benar-benar terkandung di dalam gambar, dan poligon serta komplemennya terhubung (tidak ada pulau terisolasi) sehingga input ini tidak valid:

masukkan deskripsi gambar di sini

Mencetak gol

Ini codegolf, artinya pengiriman terpendek dalam byte menang, kiriman Anda harus menemukan jumlah tepi yang benar untuk setiap kasus uji. (Dan pengajuan harus bekerja untuk kasus-kasus lain juga, optimisasi hanya untuk kasus-kasus uji tidak diperbolehkan.)

Jika Anda ingin mengirimkan solusi yang tidak menemukan nomor yang benar setiap kali, Anda dapat mengirimkannya juga, tetapi itu akan diperingkat di belakang semua pengiriman yang berkinerja lebih baik.

Harap sertakan jumlah total dalam judul kiriman Anda. (Kesalahan total jumlah perbedaan mutlak antara jumlah sisi yang nyata dan setiap output).

Uji kasus

n = 10

masukkan deskripsi gambar di sinimasukkan deskripsi gambar di sini

n = 36

masukkan deskripsi gambar di sinimasukkan deskripsi gambar di sini

n = 7

masukkan deskripsi gambar di sinimasukkan deskripsi gambar di sini

n = 5

masukkan deskripsi gambar di sinimasukkan deskripsi gambar di sini

Ini bukan ujian, hanya karena penasaran: Berapa banyak tepi yang Anda dapatkan untuk input ini?

masukkan deskripsi gambar di sini

cacat
sumber
Saya melihat banyak sudut dalam kasus uji Anda yang lebih besar dari 170 °. Misalnya, semua sudut "non-titik" (yang lebih dekat ke tengah) di bintang Anda.
Gagang Pintu
@ Doorknob Sudutnya lebih kecil yang seharusnya kurang dari 170 °.
lirtosiast
Ya, tetapi mereka lagi lebih besar dari 190 °. Inti dari pembatasan ini adalah untuk menghilangkan contoh-contoh di mana kedua pihak yang berdekatan sulit untuk dibedakan.
flawr
2
Warna apa yang merupakan bagian dalam poligon?
feersum
1
Program ini akan diumpankan ke komputer kartu punch lama, dan karena kartu punch sangat mahal saat ini, Anda lebih baik mencoba membuat program sesingkat mungkin :-)
Luis Mendo

Jawaban:

12

Python 2 + PIL, tidak ada kesalahan, 313 307 byte

from Image import*
I=open(sys.argv[1])
w,h=I.size;D=I.getdata()
B={i%w+i/w*1j for i in range(w*h)if D[i]!=D[0]}
n=d=1;o=v=q=p=max(B,key=abs)
while p-w:
 p+=d*1j;e=2*({p}<B)+({p+d}<B)
 if e!=2:e%=2;d*=1j-e*2j;p-=d/1j**e
 if abs(p-q)>5:
    t=(q-v)*(p-q).conjugate();q=p;w=o
    if.98*abs(t)>t.real:n+=1;v=p
print n

Mengambil nama file gambar pada baris perintah, dan mencetak hasilnya ke STDOUT.

Memberikan hasil yang benar untuk semua tes, dan n = 28 untuk lingkaran.

Penjelasan

Algoritma ini bekerja dengan berjalan di sepanjang perimeter poligon, dan menghitung jumlah simpul yang ditemui (terdeteksi sebagai perubahan arah). Kita mulai pada piksel yang paling jauh dari asalnya,, oyang dijamin sebagai titik, dan oleh karena itu, berdekatan dengan tepi (yaitu, batas antara piksel latar depan dan piksel latar belakang). Kami melacak posisi kami,, ptitik terbaru v, dan "pos pemeriksaan" terbaru q, yang semuanya awalnya sama dengan o. Kami juga melacak arah tepi d,, relatif terhadap piksel saat ini; dawalnya menunjuk ke timur, yang merupakan arah yang aman, karena kita tahu ada ujung ke timuro, atau yang tidak akan terjauh dari asalnya. Kami bergerak di sepanjang tepi, dalam arah yang tegak lurus d, sehingga dmengarah ke kiri, yaitu, dalam arah searah jarum jam. Setiap kali kita "jatuh dari tepi", yaitu, dalam situasi apa pun di pluar poligon, atau di mana piksel di sebelah kiri kita (yaitu, ke arah d) ada di dalam poligon, kami menyesuaikan pdan dsesuai sebelum melanjutkan.

Setiap kali jarak antara pdan pos pemeriksaan terakhir q,, menjadi lebih besar dari 5, kami mencoba menentukan apakah kami melewati titik di antara qdan p: Kami membandingkan sudut antara vq(yaitu, vektor dari vke q), yang merupakan arah umum dari sisi poligon kami berjalan bersama ketika kami mencapai pos pemeriksaan terakhir, dan qp, perpindahan antara pos pemeriksaan terakhir dan posisi saat ini. Jika sudut lebih besar dari sekitar 10 °, kami menyimpulkan bahwa kami berjalan di sisi yang berbeda dari poligon, menambah jumlah titik, dan mengatur v, titik saat ini, untuk p. Di setiap pos pemeriksaan, terlepas dari apakah kami mendeteksi titik atau tidak, kami memperbarui q, pos pemeriksaan terakhir, kep. Kami melanjutkan dengan cara ini sampai kami tiba kembali di o, titik awal, dan mengembalikan jumlah simpul yang ditemukan (perhatikan bahwa jumlah titik awalnya 1, karena titik awal o, itu sendiri merupakan titik.)

Gambar di bawah ini menunjukkan simpul yang terdeteksi. Perhatikan bahwa pengambilan p, posisi saat ini di setiap pos pemeriksaan, karena posisi titik baru tidak optimal, karena titik sebenarnya mungkin berada di antara titik pemeriksaan terakhir q,, dan p, di sepanjang perimeter. Seperti yang Anda lihat, semua simpul selain yang pertama (umumnya, simpul kanan-bawah) sedikit tidak aktif. Memperbaiki ini akan membutuhkan lebih banyak byte, tetapi ini tampaknya bekerja dengan cukup baik. Meski begitu, agak sulit untuk tidak berpakaian dengan hanya empat test case.

n = 10 n = 36 n = 7 n = 5 Lingkaran

Elo
sumber
Terima kasih atas penjelasan terperinci ini! Saya suka ilustrasi Anda!
flawr
Jika ada tepi di sebelah timur o, bukankah ujung lainnya akan lebih jauh dari asalnya?
aditsu
1
@ Aditsu Saya pikir terminologinya mungkin sedikit membingungkan di sini. Kita berbicara tentang sisi - sisi poligon, dalam arti geometris, dan ujung - ujung (kumpulan piksel yang terdiri dari) poligon, sebagai grafik raster. oadalah piksel latar depan terjauh dari asalnya, jadi piksel di sebelah timurnya harus merupakan piksel latar belakang, maka kami mengatakan bahwa ada tepi di sebelah timur o.
Ell