巻数を計算する


15

巻数は、観察者が所定の閉じた経路を追従させておく必要があり、正味反時計回りの回転の整数です。時計回りの回転は、巻数に向かってマイナスにカウントされることに注意してください。パスは自己交差できます。

いくつかの例(Wikipediaから恥知らずに取られた)を以下に示します。

ここに画像の説明を入力してください

あなたの目標は、与えられたパスの曲がりくねった数を計算することです。

入力

観測者は原点に(0,0)いると想定されます。

入力は、任意の入力ソースからの点の有限シーケンス(整数のペアのような)であり、区分的な線形パスを記述します。必要に応じて、これを整数の1Dシーケンスにフラット化し、入力をスウィズルして、すべてのy座標/逆の前にすべてのx座標を取得することもできます。入力を複素数として取得することもできますa+b i。パスは自己交差する場合があり、長さゼロのセグメントを含む場合があります。最初の点はパスの開始点であり、正のx軸上のどこかにあると想定されます。

パスのどの部分も原点と交差しません。パスは常に閉じられます(つまり、最初のポイントと失われたポイントは同じです)。あなたのコードは最後のポイントを暗示しているか、それを含める必要があるかもしれません。

たとえば、好みに応じて、両方の入力が同じ正方形を指定します。

暗黙のエンドポイント

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

明示的なエンドポイント

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

出力

出力はワインディング番号の単一の整数です。これは、任意のソース(戻り値、標準出力、ファイルなど)に対するものです。

すべての例には、エンドポイントが明示的に定義されており、x、yのペアとして指定されています。ちなみに、暗黙的に定義されたエンドポイントを想定し、出力が同じであることを前提として、これらの例をコードに直接入力することもできます。

1.基本テスト

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

出力

1

2.反復ポイントテスト

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

出力

1

3.時計回りテスト

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

出力

-1

4.外部テスト

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

出力

0

5.混合ワインディング

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

出力

2

得点

これはコードゴルフです。最短のコードが勝ちます。標準の抜け穴が適用されます。巻数を計算するように特別に設計されていない限り、組み込み関数を使用できます。


2
入力が複素数とすることができる(例えばまたはそれらの文字列表現、"1-i"または"1-1i"?)
レベル川セント

はい、あらゆるタイプのペアが許可されます。
helloworld922

回答:


10

ES6、83バイト

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

複素数として解釈されるポイントのペアの配列を入力として受け取ります。各ポイントを角度に変換するのではなく、ポイントを前のポイントで除算し、Math.atan2が-πとπの間の角度に変換するため、パスの巻き方が自動的に決定されます。角度の合計は、巻き数の2π倍になります。

Math.atan2は引数のスケールを気にしないので、実際には完全な除算を実行せず、z / w = (z * w*) / (w * w*)代わりに各ポイントに前のポイントの複素共役を掛けます。

編集:@ edc65のおかげで4バイトを保存しました。


素晴らしくて速い。そして、私はあなたの数学を理解していません。しかしreduce、ほとんど常に悪い選択です。
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/2代わりにmapまたはreduceを使用します。とにかく私の投票がある
-edc65

@ edc65ありがとう。reduceMath.atan2(0,0)が0であることに気づかなかったために使用しました(0の1つが実際に-0であるかどうかに依存します)。数学は複素除算に基づいています。z / w = z * w* / |w|²、しかし、私は大きさを気にしないので、それは単に複素共役による乗算です。また、Math.atan2は(y、x)引数をわずかに混乱させて受け入れます。
ニール

私はコードを理解していないと認めますが、説明が正確であれば、答えは間違っていると思います。実際、このパスからポイントを入力した場合(わかりやすくするために写真を示しています)、ワインディング番号は1ですが、問題は2を出力します。
Wojowu

あなたの写真のためにそうではなく、多角形の外角よりも、原点から測定されるように申し訳ありません@Wojowu、私はポイント間の角度を意味し、私のコードは確かに1としての答えを計算する必要がある
ニール

3

MATL、11バイト

X/Z/0)2/YP/

入力は、終点を含む一連の複素数です。

オンラインでお試しください!

説明

ほとんどの作業はZ/関数(unwrap)によって行われます。関数()は、pi以上の絶対ジャンプを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とJellyは最近、ほとんどの重要な課題をほぼ結び付けています。私は感銘を受けました、あなたはほとんど
メタゴルフされていない

@ETHproductions素敵な言葉をありがとう!はい、それらはいくつかの最近の課題に結びついています。一方、私はゼリーのバイトカウントがMATL :-Dの半分程度であるかなりの数の問題を見てきました
ルイスMendo


1

Python、111

これまでの最長回答。私の動機は1)Pythonを学び、2)おそらくこれを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)))

入力は複素数のリストとして与えられます。

イデオン。

このアプローチはES6の答えに似ていると思います。

2つの複素数を乗算すると、積の引数または位相は、2つの数値の引数または位相の合計になります。したがって、複素数を別の数で除算すると、商の位相は分子と分母の位相の差になります。したがって、各ポイントと次のポイントの通過角度を計算できます。これらの角度を合計し、2πで割ると必要な巻き数が得られます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.