ウォーキングポイントを並べ替える最短のコード


8

課題は、ポイントのリストを指定して、それらがこの順序で接続されている場合、交差しないように並べ替えることです。

入力フォーマット(標準入力から読み込み):

X Y
1 2
3 4
5 6
...

出力は入力と同じでなければなりませんが、ソートされています。

ルール:

  • どこからでも始められます。
  • 最後のポイントは最初のポイントと同じでなければならず、閉回路を形成します。
  • デカルトグリッドを考慮して行う必要があります。
  • 入力ポイントがすべて1本の線上にあるとは限りません。
  • 各線の端点は交差として数えられません。

さらにヘルプが必要な場合:

図


2
@Rusherなぜ閉回路が交差することが保証されているのですか?(OPの例にはありません)
Martin Ender 2014

2
それが単なる線の場合、基本的な解決策は、1番目と2番目の座標による並べ替えであり、ペアのデフォルトの並べ替えです。
スウィッシュ

3
@Rusher:開始点と終了点が同じであるという些細な意味を除いて、閉回路は必ずしも自己交差しません。投稿の「良い」画像は、自己交差していない閉回路を示しています。さらに、閉回路要件がない場合、この課題は完全に簡単になります。GolfScriptの6文字で解決できます。そのうち5文字はI / O処理です。
Ilmari Karonen 14

4
@Rusher:エンドポイントを共有するため、パス内の連続する 2本の線は常に交差する必要があると同様に主張できます。そのような「交差」(閉ループの端点での「交差」は1つの例です)は取るに足らないものであり、「非自己交差パス」の意味のある定義では数えられません。(とにかく、あなたが本当に徹底的になりたい場合は、各線分を定義して、始点は含むが終点は含まないようにします。問題は解決しました。)
Ilmari Karonen 14

2
編集された質問は、取るに足りないほど終了するに値しました。編集によって問題からすべての課題が取り除かれるべきではありません。そのため、ロールバックしました。誰もが同意しない場合は、メタでこれについて喜んで議論します。
Peter Taylor

回答:


9

Mathematica- 20 30文字

仕分け部分だけ

SortBy[%, ArcTan @@ # &]

100個のランダムポイントの生成とラインのプロットで構成されるテストコード全体

RandomReal[{-10, 10}, {100, 2}];
SortBy[%, ArcTan @@ # &];
ListPlot@% /. 
 Point[p_] :> {EdgeForm[Dashed], FaceForm[White], Polygon[p], 
   PointSize -> Large, Point[p]}

+26文字

適切な入力/出力を要求する場合、

"0 0
 4 4
 0 4
 4 0";
Grid@SortBy[%~ImportString~"Table", ArcTan @@ # &]

+2文字

追加するだけ N@

Grid@SortBy[%~ImportString~"Table", ArcTan @@ N @ # &]

上記のコードは、シンボリック式をソートするときのMathematicaの奇妙な動作のために、整数ではなく実数でのみ機能するため

N@Sort[{ArcTan[1], ArcTan[-2]}]
Sort[N@{ArcTan[1], ArcTan[-2]}]

{0.785398, -1.10715}
{-1.10715, 0.785398}

編集ポイントが原点の周りにない場合は機能しないので、ポイントの中心にシフトする必要があることもわかった

SortBy[%, ArcTan @@ N[# - Mean@%] &]

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


「質量の中心」と一致する3つのポイントがある反例を見つけようとしました。それらはすべて同じ逆正接を持つため、コードによって順序が決定されないため、接続が重複する可能性があります。ただし、スニペットは常にそれらのケースを裏返しにソートするように見えますArcTanが、実際の結果は最後のビットまで同じです。それがなぜか知っていますか?(あなたがそれをいじりたい場合はここにそのようなケースがあります{{1, 2}, {2, 4}, {3, 6}, {-5, 5}, {-6, -12}, {5, -5}})。
マーティンエンダー2014

1
@ m.buettner SortByドキュメントから:f [e_i]の一部が同じである場合、対応するe_iの正規の順序が使用されます。
2014

なんて都合のいい!:)
マーティンエンダー2014

5

質問が変更されたため、この回答には閉じたパスがある場合とない場合の異なるバージョンが含まれています。

Perl、オープンパス、69バイト

print"@$_$/"for sort{$$a[0]<=>$$b[0]||$$a[1]<=>$$b[1]}map{[/\S+/g]}<>

STDINでは、各点は空白で区切られた座標で線として期待されます。

Perlが数値(浮動小数点数を含む)として解釈する任意の数値形式がサポートされています。

例:

0 0
4 4
0 4
4 0
-2 1
2 -2
2 4
3.21 .56
.035e2 -7.8
0 2

出力:

-2 1
0 0
0 2
0 4
2 -2
2 4
3.21 .56
.035e2 -7.8
4 0
4 4

結果

未ゴルフ:

print "@$_$/" for            # print output line      
    sort {                   # sort function for two points $a and $b
        $$a[0] <=> $$b[0]    # compare x part                           
        || $$a[1] <=> $$b[1] # compare y part, if x parts are identical
    }
    map { [/\S+/g] }         # convert input line to point as array reference
    <>                       # read input lines               

回路バリアント

最初の質問版では、回路を作るための最後の点と最初の点の間に関係がありました。

中心は存在しないポイント、253バイト

中心がポイントの1つである場合、このバリアントは失敗する可能性があります。例3を参照してください。

編集:

  • 彼の答えは、クロスフリー回路を確実にするために、ポイントが原点の中心に置かれるべきであることに気づきました:

    • ソートには座標変換が必要です。
    • 数値の元の文字列表現は、出力用に保持する必要があります。
  • バグ修正:負のx軸の特殊なケースに正のx軸が含まれていました。

print"$$_[2] $$_[3]$/"for sort{($X,$Y)=@$a;($x,$y)=@$b;(!$X&&!$Y?-1:0)||!$x&&!$y||!$Y&&!$y&&$X<0&&$x<0&&$X<=>$x||atan2($Y,$X)<=>atan2($y,$x)||$X**2+$Y**2<=>$x**2+$y**2}map{[$$_[0]-$M/$n,$$_[1]-$N/$n,@$_]}map{$n++;$M+=$$_[0];$N+=$$_[1];$_}map{[/\S+/g]}<>

例1:

4 4
-2 0
2 0
1 1
4 0
-2 -2
-3 -1
1 -2
3 0
2 -4
0 0
-1 -2
3 3
-3 0
2 3
-5 1
-6 -1

出力1:

0 0
-6 -1
-3 -1
-2 -2
-1 -2
1 -2
2 -4
2 0
3 0
4 0
1 1
3 3
4 4
2 3
-5 1
-3 0
-2 0

結果回路1

例2:

数値表現と座標変換のテスト。

.9e1 9
7 7.0
8.5 06
7.77 9.45

出力2:

7 7.0
8.5 06
.9e1 9
7.77 9.45

結果回路2

未ゴルフ:

print "$$_[2] $$_[3]$/" for sort { # print sorted points
    ($X, $Y) = @$a;                # ($X, $Y) is first point $a
    ($x, $y) = @$b;                # ($x, $y) is second point $b
    (!$X && !$Y ? -1 : 0) ||       # origin comes first, test for $a
    !$x && !$y ||                  # origin comes first, test for $b
    !$Y && !$y && $X < 0 && $x < 0 && $X <=> $x ||
        # points on the negative x-axis are sorted in reverse order
    atan2($Y, $X) <=> atan2($y, $x) ||
        # sort by angles; the slope y/x would be an alternative,
        # then the x-axis needs special treatment
    $X**2 + $Y**2 <=> $x**2 + $y**2
        # the (quadratic) length is the final sort criteria
}
map { [ # make tuple with transformed and original coordinates
        # the center ($M/$n, $N/$n) is the new origin
        $$_[0] - $M/$n,  # transformed x value
        $$_[1] - $N/$n,  # transformed y value
        @$_              # original coordinates
] }
map {
    $n++;                # $n is number of points
    $M += $$_[0];        # $M is sum of x values
    $N += $$_[1];        # $N is sum of y values
    $_                   # pass orignal coordinates through
}
map {                    # make tuple with point coordinates
    [ /\S+/g ]           # from non-whitespace in input line
}
<>                       # read input lines

制限なし、325バイト

print"$$_[2] $$_[3]$/"for sort{($X,$Y)=@$a;($x,$y)=@$b;atan2($Y,$X)<=>atan2($y,$x)||$X**2+$Y**2<=>$x**2+$y**2}map{[$$_[0]-$O/9,$$_[1]-$P/9,$$_[2],$$_[3]]}map{$O=$$_[0]if$$_[0]>0&&($O>$$_[0]||!$O);$P=$$_[1]if$$_[1]>0&&($P>$$_[1]||!$P);[@$_]}map{[$$_[0]-$M/$n,$$_[1]-$N/$n,@$_]}map{$n++;$M+=$$_[0];$N+=$$_[1];$_}map{[/\S+/g]}<>

以前のバージョンでは、中心が最初に配置され、負の軸の最後のポイントが逆の順序で並べ替えられて、再び中心にクロスフリーになります。ただし、最後の点が別の線上にある可能性があるため、これでは十分ではありません。したがって、次の例3は失敗します。

これは、中央揃えの原点を少し上下に移動することで修正されます。センタリングのため、x値が正の点とy値が正の点が少なくとも1つ必要です。したがって、正のx値とy値の最小値が取得され、9分の1に削減されます(半分または3分の1で十分な場合があります)。このポイントは既存のポイントの1つであってはならず、新しい原点になります。

新しい原点上にあるポイントがあるため、原点と負のx軸の特別な処理を削除できます。

例3:

-2 -2
-1 -1
-2 2
-1 1
2 -2
1 -1
2 2
1 1
0 0

出力3:

0 0
-1 -1
-2 -2
1 -1
2 -2
1 1
2 2
-2 2
-1 1

結果3

例1のソート方法が異なります。

結果1

未ゴルフ:

print "$$_[2] $$_[3]$/" for sort { # print sorted points        
    ($X, $Y) = @$a;                # ($X, $Y) is first point $a 
    ($x, $y) = @$b;                # ($x, $y) is second point $b
    atan2($Y, $X) <=> atan2($y, $x) ||
        # sort by angles; the slope y/x would be an alternative,
        # then the x-axis needs special treatment
    $X**2 + $Y**2 <=> $x**2 + $y**2
        # the (quadratic) length is the final sort criteria
}  
map { [ # make tuple with transformed coordinates
    $$_[0] - $O/9, $$_[1] - $P/9,  # new transformed coordinate
    $$_[2],  $$_[3]                # keep original coordinate
] }
map {
    # get the minimum positive x and y values 
    $O = $$_[0] if $$_[0] > 0 && ($O > $$_[0] || !$O);         
    $P = $$_[1] if $$_[1] > 0 && ($P > $$_[1] || !$P);
    [ @$_ ]               # pass tuple through
}
map { [ # make tuple with transformed and original coordinates
        # the center ($M/$n, $N/$n) is the new origin
        $$_[0] - $M/$n,  # transformed x value
        $$_[1] - $N/$n,  # transformed y value 
        @$_              # original coordinates
] }  
map {
    $n++;                # $n is number of points
    $M += $$_[0];        # $M is sum of x values 
    $N += $$_[1];        # $N is sum of y values
    $_                   # pass orignal coordinates through
}
map {                    # make tuple with point coordinates
    [ /\S+/g ]           # from non-whitespace in input line
} 
<>                       # read input lines

回路のバリアントを含めるための+1(Rusherが応答すると、要件は最終的に再び質問に入ると思います)
Martin Ender

3

GolfScript、6/13文字(オープ​​ンパス、クローズパスの49文字)

注:このソリューションは、Rusherが編集した現在のバージョンのチャレンジ用です。これは、最後のポイントから最初のポイントに戻るラインも他のラインと交差しないようにする必要がある元の課題に対する有効なソリューションではありません。以下の49文字のソリューションは、元の課題にも有効です。

~]2/$`

上記のコードは、出力が適切な形式であることを前提としています。出力形式が入力と一致する必要がある場合は、次の13文字バージョンが実行されます。

~]2/${" "*n}/

説明:

  • ~入力を評価し、数値のリストに変換します。]これらの数値を配列に収集し、2/この配列を、それぞれが1つの点を表す2つの数値のブロックに分割します。

  • $ポイントを辞書式順序で並べ替えます。つまり、最初にx座標で並べ替え、次にタイがある場合はy座標で並べ替えます。これは、パスが最初にループバックする必要がない限り、ポイント間に描かれた線が交差しないことを保証することを示すのは簡単です。

  • 5文字バージョンで`は、ソートされた配列を文字列化し、そのネイティブ文字列表現を生成します(例:)[[0 0] [0 4] [4 0] [4 4]]。長いバージョンで{" "*n}/は、各ポイントの座標をスペースで結合し、改行を追加します。

オンラインデモ:ショートバージョン / ロングバージョン


PS 次に、元の問題の49文字の解決策を示します。パスを閉じる必要があります。

~]2/$.0=~:y;:x;{~y-\x-.+.@9.?*@(/\.!@@]}${" "*n}/

これはHeiko OberdiekのPerlソリューションと同じように機能しますが、trig関数を使用する代わりに、このコードは勾配(yy 0)/(xx 0)でポイントを並べ替えます。ただし、(x 0y 0)は、最小のx座標を持つポイントです(最小のxに対して複数のポイントが関連付けられている場合は、最小のy 座標)。

GolfScriptは、浮動小数点をサポートしていないので、斜面が固定定数9を乗じて9 = 387420489.(それが十分では精度がない場合は、交換することができます9とを9999に乗数をオンにする99 ≈3.7×10 197。)もあります結合を(x座標で)壊し、Heikoのソリューションのように、x = x 0のポイントが最後にy座標の降順で並べ替えられるようにするための追加コード。

繰り返しになりますがここにオンラインデモがあります。


1

Mathematica、35歳

これは、一意のポイントのすべてのリストで機能します。

s=StringSplit;Grid@Sort@s@s[%,"\n"]

あなたは「標準入力から読み取る」と言うので、Mathematicaでは「最後の出力から読み取る」と仮定しています。

入力(最後の出力):

"0 0
4 4
0 4
4 0"

出力:

0 0
0 4
4 0
4 4

入力と出力を「改行」形式にする必要がない場合、これは6文字に縮小できます。

Sort@%

最後の出力が2次元配列であると仮定して、最後の出力を入力として受け取ります。

入力(最後の出力):

{{0,0},{4,4},{0,4},{4,0}}

出力:

{{0,0},{0,4},{4,0},{4,4}}

Sort同じことをするだけじゃないの?
2014

@swish私が使用しているSortByので、「x」の値と「y」の値に関して簡単にソートできます。
kukac67 2014

しかし、sortは同じことを行い、xとyでソートします。
2014

名前をStringSplit再度変更し、中置構文を使用すると、7文字を保存できますSort@(s=StringSplit)@%~s~"\n"
マーティンエンダー2014

@swish「ソート」について教えてくれてありがとう。これによりコードが大幅に短縮されました...
kukac67 2014

1

PHP(175 109 100文字)

while(fscanf(STDIN,'%d%d',$a,$b))$r[]=sprintf('%1$04d %2$04d',$a,$b);sort($r);echo implode('
',$r);

OK、PHPは最高のゴルフ言語ではありませんが、試してみました。

次に出力例をいくつか示します。

0000 0000
0000 0004
0004 0000
0004 0004

何をするかというと、以前のゼロでフォーマットされた文字列に情報を入れます。
次に、ポイントをテキストでソートします。
PS上記の数値では失敗します9999


0

Python 2.7、42B

import sys
print''.join(sorted(sys.stdin))

本当に簡単にはできませんでした。STDINの読み取り、行のソート、行の印刷。注意:私は質問の正確なI / O要件を尊重しましたが、手動でSTDINにCTRL+d入力している場合は、を押して入力を終了する必要があります。

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