Calcola il numero di avvolgimento


15

Il numero di avvolgimento è il numero intero di giri netti in senso antiorario che un osservatore deve aver fatto per seguire un determinato percorso chiuso. Si noti che eventuali giri in senso orario contano negativamente verso il numero di avvolgimento. Il percorso è autorizzato a intersecarsi da soli.

Di seguito alcuni esempi (presi spudoratamente da Wikipedia):

inserisci qui la descrizione dell'immagine

Il tuo obiettivo è calcolare il numero di avvolgimento per un determinato percorso.

Ingresso

Si presume che l'osservatore sia all'origine (0,0).

L'input è una sequenza finita di punti (simile a una coppia di numeri interi) da qualsiasi sorgente di input desiderata che descrive il percorso lineare saggio. Puoi appiattirlo in una sequenza 1D di numeri interi, se lo desideri, e puoi anche far scorrere l'input per prendere tutte le coordinate x prima di tutte le coordinate y / viceversa. Puoi anche prendere l'input come numero complesso a+b i. Il percorso può intersecarsi da solo e può contenere segmenti di lunghezza zero. Il primo punto è l'inizio del percorso e si presume che si trovi da qualche parte sull'asse x positivo.

Nessuna parte del percorso interseca l'origine. Il percorso sarà sempre chiuso (ovvero il primo e il punto perso sono gli stessi). Il tuo codice può implicare l'ultimo punto o richiedere che sia incluso.

Ad esempio, a seconda delle preferenze, entrambi gli input specificano lo stesso quadrato:

punto finale implicito

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

punto finale esplicito

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

Produzione

L'output è un singolo numero intero per il numero di avvolgimento. Questo può essere per qualsiasi fonte (valore di ritorno, stdout, file, ecc.).

Esempi

Tutti gli esempi hanno il punto finale definito esplicitamente e sono indicati come coppie x, y. Per inciso, dovresti essere anche in grado di inserire direttamente questi esempi in qualsiasi codice assumendo punti finali definiti in modo implicito e gli output dovrebbero essere gli stessi.

1. Test di base

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

Produzione

1

2. Test del punto ripetuto

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

Produzione

1

3. Test in senso orario

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

Produzione

-1

4. Test esterno

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

Produzione

0

5. Avvolgimento misto

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

Produzione

2

punteggio

Questo è il codice golf; vince il codice più breve. Si applicano scappatoie standard. È possibile utilizzare qualsiasi funzione incorporata purché non sia stata progettata specificamente per calcolare il numero di avvolgimento.


2
Gli input possono essere presi come numeri complessi (o una loro rappresentazione in formato stringa, come "1-i"o "1-1i"?)
Level River St

sì, è consentito qualsiasi tipo di coppia.
helloworld922

Risposte:


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

Prende come input una matrice di coppie di punti che vengono interpretati come numeri complessi. Anziché convertire ciascun punto in un angolo, i punti vengono divisi per il punto precedente, che Math.atan2 converte quindi in un angolo tra -π e π, determinando automaticamente in che modo si snoda il percorso. La somma degli angoli è quindi 2π volte il numero di avvolgimento.

Dato che a Math.atan2 non interessa la scala dei suoi argomenti, in realtà non eseguo l'intera divisione, z / w = (z * w*) / (w * w*)ma semplicemente moltiplico ogni punto per il complesso coniugato del punto precedente.

Modifica: salvato 4 byte grazie a @ edc65.


Bello e veloce. E non capisco la tua matematica. Ma reduceè quasi sempre una cattiva scelta.
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/2usando invece la mappa o riduci. Hai comunque il mio voto
edc65

@ edc65 Grazie; Ho usato reduceperché non mi rendevo conto che Math.atan2 (0,0) è 0. (Beh, dipende se uno dei tuoi 0 è in realtà -0.) La matematica si basa su una divisione complessa, che normalmente viene calcolata come z / w = z * w* / |w|², ma non mi interessa la grandezza, quindi è solo una moltiplicazione per il coniugato complesso. Anche Math.atan2 accetta in modo leggermente confuso argomenti (y, x).
Neil,

Ammetto di non capire il codice, ma se la tua descrizione è accurata, credo che la tua risposta sia sbagliata. Infatti, se hai inserito punti da questo percorso (sto dando un'immagine per maggiore chiarezza) il numero di avvolgimento è 1, mentre il tuo problema produrrebbe 2.
Wojowu

@Wojowu Spiacente, intendevo l'angolo tra i punti misurato dall'origine, piuttosto che gli angoli esterni del poligono, quindi per la tua foto, il mio codice dovrebbe effettivamente calcolare la risposta come 1.
Neil

3

MATL , 11 byte

X/Z/0)2/YP/

L'input è una sequenza di numeri complessi incluso il punto finale.

Provalo online!

Spiegazione

La maggior parte del lavoro viene eseguita dalla Z/funzione ( unwrap), che sposta gli angoli in radianti modificando i salti assoluti maggiori o uguali a pi al loro complemento 2 * pi.

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

1
MATL e Jelly hanno praticamente legato la maggior parte delle sfide di matematica recentemente. Sono impressionato, hai quasi superato la meta-golf del linguaggio di Dennis ...
ETHproductions

@ETHproductions Grazie per le tue belle parole! Sì, sono stati legati in alcune recenti sfide. D'altra parte, ho visto alcuni problemi in cui il conteggio dei byte di Jelly è circa la metà di MATL :-D
Luis Mendo

2

Gelatina, 11 byte

æAI÷ØPæ%1SH

Questo accetta input come un elenco di coordinate y e un elenco di coordinate x.

Provalo qui .


1

Python, 111

La risposta più lunga finora. Le mie motivazioni sono 1) imparare Python e 2) possibilmente portarlo su 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)))

L'input viene fornito come un elenco di numeri complessi.

Ideone.

Penso che l'approccio sia simile alla risposta ES6.

Quando si moltiplicano 2 numeri complessi, l'argomento o la fase del prodotto è la somma dell'argomento o della fase dei due numeri. Pertanto, quando un numero complesso viene diviso per un altro, la fase del quoziente è la differenza tra le fasi del numeratore e del denominatore. In questo modo possiamo calcolare l'angolo attraversato per ciascun punto e il punto successivo. Sommare questi angoli e dividere per 2π fornisce il numero di avvolgimento richiesto.

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.