Hitung angka belitan

15

The nomor berliku adalah jumlah bilangan bulat dari revolusi berlawanan bersih pengamat harus dilakukan untuk mengikuti jalan tertutup diberikan. Perhatikan bahwa setiap putaran searah jarum jam dihitung negatif ke arah angka belitan. Jalan itu diizinkan untuk bersinggungan sendiri.

Beberapa contoh (tanpa malu-malu diambil dari Wikipedia) diberikan di bawah ini:

masukkan deskripsi gambar di sini

Tujuan Anda adalah menghitung angka yang berliku untuk jalur yang diberikan.

Memasukkan

Pengamat dianggap asal (0,0).

Input adalah urutan titik yang terbatas (pasangan-seperti angka integer) dari sumber input yang diinginkan yang menggambarkan jalur linier yang bijaksana. Anda dapat meratakan ini ke dalam urutan bilangan bulat 1D jika diinginkan, dan juga dapat mengurangi input untuk mengambil semua koordinat x sebelum semua koordinat y / sebaliknya. Anda juga dapat mengambil input sebagai bilangan kompleks a+b i. Path mungkin bersinggungan sendiri dan mungkin berisi segmen dengan panjang nol. Titik pertama adalah awal jalan dan diasumsikan terletak di suatu tempat pada sumbu x positif.

Tidak ada bagian jalan yang akan memotong titik asal. Path akan selalu ditutup (yaitu titik pertama dan yang hilang adalah sama). Kode Anda mungkin menyiratkan poin terakhir atau mengharuskannya untuk dimasukkan.

Misalnya, tergantung pada preferensi Anda, kedua input menentukan kotak yang sama:

titik akhir tersirat

1,0
1,1
-1,1
-1,-1
1,-1

titik akhir eksplisit

1,0
1,1
-1,1
-1,-1
1,-1
1,0

Keluaran

Outputnya adalah bilangan bulat tunggal untuk nomor belitan. Ini mungkin untuk sumber mana saja (nilai pengembalian, stdout, file, dll.).

Contohnya

Semua contoh memiliki titik akhir yang didefinisikan secara eksplisit dan diberikan sebagai pasangan x, y. Secara kebetulan, Anda harus dapat juga secara langsung memasukkan contoh-contoh ini ke dalam kode apa pun dengan asumsi titik akhir yang didefinisikan secara implisit dan hasilnya harus sama.

1. Tes dasar

1,0
1,1
-1,1
-1,-1
1,-1
1,0

Keluaran

1

2. Tes poin berulang

1,0
1,0
1,1
1,1
-1,1
-1,1
-1,-1
-1,-1
1,-1
1,-1
1,0

Keluaran

1

3. Tes searah jarum jam

1,0
1,-1
-1,-1
-1,1
1,1
1,0

Keluaran

-1

4. Tes di luar

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

Keluaran

0

5. Campuran berliku

1,0
1,1
-1,1
-1,-1
1,-1
1,0
1,-1
-1,-1
-1,1
1,1
1,0
1,1
-1,1
-1,-1
1,-1
1,0
1,1
-1,1
-1,-1
1,-1
1,0

Keluaran

2

Mencetak gol

Ini adalah kode golf; kode menang paling pendek. Celah standar berlaku. Anda dapat menggunakan fungsi bawaan apa pun asalkan tidak dirancang secara khusus untuk menghitung angka belitan.

helloworld922
sumber
2
Dapatkah input diambil sebagai bilangan kompleks (atau representasi string dari mereka, seperti "1-i"atau "1-1i"?)
Level River St
ya, semua jenis pasangan diizinkan.
helloworld922

Jawaban:

10

ES6, 83 byte

a=>a.map(([x,y])=>r+=Math.atan2(y*b-x*c,y*c+x*b,b=x,c=y),b=c=r=0)&&r/Math.PI/2

Dibawa sebagai input, sebuah array pasangan poin yang ditafsirkan sebagai bilangan kompleks. Daripada mengubah setiap titik menjadi sudut, titik-titik tersebut dibagi dengan titik sebelumnya, yang kemudian dikonversi oleh Math.atan2 menjadi sudut antara -π dan π, sehingga secara otomatis menentukan ke arah mana jalannya berliku. Jumlah sudut kemudian 2π kali dari jumlah belitan.

Karena Math.atan2 tidak peduli dengan skala argumennya, saya tidak benar-benar melakukan pembagian penuh, tetapi z / w = (z * w*) / (w * w*)saya hanya mengalikan setiap poin dengan konjugasi kompleks dari poin sebelumnya.

Sunting: Disimpan 4 byte berkat @ edc65.

Neil
sumber
Bagus dan cepat. Dan saya tidak mengerti matematika Anda. Tetapi reducehampir selalu merupakan pilihan yang buruk.
edc65
a=>a.map(([x,y])=>r+=Math.atan2(y*b-x*c,y*c+x*b,b=x,c=y),b=c=r=0)&&r/Math.PI/2menggunakan peta saja atau kurangi. Anda tetap memilih saya
edc65
@ edc65 Terima kasih; Saya menggunakan reducekarena saya tidak menyadari bahwa Math.atan2 (0,0) adalah 0. (Yah, itu tergantung pada apakah salah satu dari 0s Anda sebenarnya -0.) Matematika didasarkan pada divisi kompleks, yang biasanya dihitung sebagai z / w = z * w* / |w|², tapi saya tidak peduli tentang besarnya, jadi itu hanya perkalian dengan konjugat kompleks. Math.atan2 juga sedikit membingungkan menerima (y, x) argumen.
Neil
Saya akui saya tidak mengerti kodenya, tetapi jika deskripsi Anda akurat, maka saya yakin jawaban Anda salah. Memang, jika Anda memasukkan poin dari jalur ini (saya memberikan gambaran untuk kejelasan yang lebih besar) maka angka berliku adalah 1, sedangkan masalah Anda akan menghasilkan 2.
Wojowu
@ Woojowu Maaf, maksud saya sudut antara titik-titik yang diukur dari asal, bukan sudut eksternal poligon, jadi untuk gambar Anda, kode saya memang harus menghitung jawabannya sebagai 1.
Neil
3

MATL , 11 byte

X/Z/0)2/YP/

Input adalah urutan bilangan kompleks termasuk titik akhir.

Cobalah online!

Penjelasan

Sebagian besar pekerjaan dilakukan oleh Z/function ( unwrap), yang membuka sudut dalam radian dengan mengubah lompatan absolut lebih besar dari atau sama dengan pi ke komplemen 2 * pi mereka.

X/       % compute angle of each complex number
Z/       % unwrap angles
0)       % pick last value. Total change of angle will be a multiple of 2*pi because 
         % the path is closed. Total change of angle coincides with last unwrapped
         % angle because the first angle is always 0
2/       % divide by 2
YP/      % divide by pi
Luis Mendo
sumber
1
MATL dan Jelly telah mengikat banyak tantangan matematika akhir-akhir ini. Saya terkesan, Anda hampir tidak menggunakan bahasa Dennis ...
ETHproduksi
@ETHproductions Terima kasih atas kata-kata baik Anda! Ya, mereka telah terikat dalam beberapa tantangan baru-baru ini. Di sisi lain, saya telah melihat beberapa masalah di mana jumlah byte Jelly sekitar setengah dari MATL :-D
Luis Mendo
2

Jelly, 11 byte

æAI÷ØPæ%1SH

Ini mengambil input sebagai daftar koordinat y dan daftar koordinat x.

Coba di sini .

lirtosiast
sumber
1

Python, 111

Jawaban terpanjang sejauh ini. Motivasi saya adalah 1) belajar python dan 2) mungkin port ini ke pyth.

from cmath import *
q=input()
print reduce(lambda x,y:x+y,map(lambda (x,y):phase(x/y)/pi/2,zip(q[1:]+q[:1],q)))

Input diberikan sebagai daftar bilangan kompleks.

Ideone.

Saya pikir pendekatannya mirip dengan jawaban ES6.

Ketika 2 bilangan kompleks dikalikan, argumen atau fase produk adalah jumlah dari argumen atau fase dari dua angka. Jadi ketika bilangan kompleks dibagi dengan yang lain, maka fase hasil bagi adalah perbedaan antara fase pembilang dan penyebut. Dengan demikian kita dapat menghitung sudut yang dilalui untuk setiap titik dan titik berikutnya. Jumlahkan sudut-sudut ini dan bagi dengan 2π memberikan angka berliku yang diperlukan.

Trauma Digital
sumber