一連のターンが与えられた最短の自己回避経路


15

右または左ターンの空でないシーケンスが与えられた場合に、それらのターンを持つ2Dラティス上の最短の自己回避パスの長さを出力するプログラムまたは関数を記述します。

入力は、各文字があることで、文字列として扱われるべきRか、Lそれぞれ右左折のために。

出力は整数、つまり指定されたターンの最短経路の長さでなければなりません。

これはゴードゴルフです-最短のコードが勝ちます。

与えられた入力

LLLLLLLLLLRRL

最短パスは次のとおりです(から開始#):

+-+-+-+-+-+-+
|           |  
+ . + +-+-+ +
|   | |   | |  
+ +-+ + #-+ +
| |   |     |  
+ +-+ +-+-+-+
|   |          
+-+-+ . . . .

そして、このパスの全長は29(sではなく、s -|sを数える+)です。

テストケース

L 2
RRRRRRRRRR 23
LRRLRLRRRRL 15
LLRRLRRRRLLL 17
LLRRRRRRLLLL 21
LLLLRLLRRLLRL 16
LRLRLRLLRLRRL 14
RLLRRRRLLRRLRL 17
RRRRLLRLLLRLRL 20
LLLLRRLRLRRRLRL 19
RRRLRRRLRRLRLRL 20

コーナーでも自己回避します(たとえば、メインを南に歩いてエルムに向かって東に曲がり、その後メインを北に歩いてエルムに向かって西に曲がってエルムに入るのは禁止です)。
msh210 2016年

2
@ msh210はい、コーナーでも同じポイントに2回アクセスすることはできません。
cardboard_box

回答:


8

プロローグ、284バイト

e(S,[0|X]):-e(S,X).
e([A|S],[A|X]):-S=X;e(S,X).
v(X/Y,76,Y/Z):-Z is -X.
v(X/Y,82,Z/X):-Z is -Y.
v(D,0,D).  
c([],0/0-0/1,[0/0]).
c([H|T],K/L-D/E,[K/L|C]):-c(T,I/J-X/Y,C),v(X/Y,H,D/E),K is I+X,L is J+Y,\+member(K/L,C).
n(X):-X=0;n(Y),X#=Y+1.
p(S,L):-n(L),length(X,L),e([0|S],X),c(X,_,_).

これはアルゴリズムの非常に簡単なステートメントであり、かなり非効率的です(ほとんどのテストケースは実行されましたが、すべてのテストケースが妥当な時間内に実行されたわけではありません)。これは、出力の可能な長さをすべて1以上から生成することで機能します(n); 入力と一致する、その長さの左/前/右のすべての可能なシーケンスを生成します(で実装されeます。新しいパスはと呼ばれますX)。次にc、有効な最初のパスをチェックします(は、v左と右の影響を処理するためにを呼び出して、xデルタとyデルタをオンにします)。戻り長は、で見られる最初の出力です。L。(+2に戻るときに、関数が他の長さの可能な出力を返さないようにしたい場合は、+ 2のペナルティ。Prologの特異関数がどのように返されるかを数える必要があるかどうかは明確ではありません。)

ここではゴルフのトリックの方法はあまりありませんが、いくつかあります。nパーサーを混乱させることなく、より多くの空白を削除できるため、制約ソルバーで実装されました。これには、GNU Prologを使用する必要があるかもしれません。(c負の数を処理する必要があるため、同じことを行うことはできませんでした。)の実装はe、複数の方法でリストを照合することにより、必要とするよりもかなり効率が良くありません。より効率的なのe([],[]).は6バイト長くなります(S=X;オンライン2を削除することはできますが、10の損失と比較して4の利得にすぎません)。座標や方向を全体または一部だけX/Yに一致させるために、それらを(つまり、一致する可能性のある未評価のAST として)表現し、中置記法を使用できるようにします。

Prolog、256バイト、非効率すぎて簡単にテストできない

もちろん、これはPrologであるため、関数の多くは可逆的であり、たとえばc、原点から特定の座標ペアへのすべてのパスを生成するために使用できます。また、c自然に最短から最長まで生成します。つまり、最小の長さを明示的に要求する代わりに、どこにでも行くすべてのパスcを生成して、入力と一致する最初のパスを探すことができます。

e(S,[0|X]):-e(S,X).
e([A|S],[A|X]):-S=X;e(S,X).
v(X/Y,76,Y/Z):-Z is -X.
v(X/Y,82,Z/X):-Z is -Y.
v(D,0,D).
c([],0/0-0/1,[0/0]).
c([H|T],K/L-D/E,[K/L|C]):-c(T,I/J-X/Y,C),v(X/Y,H,D/E),K is I+X,L is J+Y,\+member(K/L,C).
p(S,L):-c(X,_,_),length(X,L),e([0|S],X).

これには指数関数的なパフォーマンスがあります(O(3 n)、nは出力)。しかし、私はいくつかの小さなテストでそれを検証することに成功しました(私のコンピューターでは、出力14に約7秒、出力15に約20秒かかります)。


これをTIOで機能させることはできませんでしたが、ばかげたことをしているかもしれません。
Peter Kagey

@PeterKagey私はプロローグをあまり知りませんが、これはうまくいくと思います。入力 "LRRLRLRRRRL"の場合
H.PWiz

4

Pyth、36バイト

ff{I.u+NYY0f>r8YlQ.C+1*M._m^.j)hCdQT

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

これはかなり遅いですが、動作し、短い入力には十分高速です。

プログラムは、方向を複素数単位(1、-1、i、-i)として表し、ポイントを複素数として表すことによって機能します。最初にターンのリストをルートのリストに変換し、次にnステップのすべてのリストを生成し、各ターンの間に少なくとも1つのステップがあるものをフィルタリングし、ルートを訪問したポイントのリストに変換し、そのリストがユニーク。成功するまでループでnをインクリメントします。

複素数にマッピング:

m^.j)hCdQ
m       Q    Map over the input
      Cd     Convert to ASCII codepoint
     h       Increment
 ^.j)        Raise i to that power.

以来LASCIIコードポイント76を有しており、RASCIIコードポイント82を持ち、これがマッピングさLiしてRまで-i

絶対方向へのマッピング:

+1*M._ ...
    ._      Form all prefixes
  *M        Map each to its product
+1          Add the first direction, before any turns

各ターンの間に少なくとも1つのステップがあるnステップのリストを形成する

f>r8YlQ.C ... T
       .C     T    Form all list of T steps
f                  Filter for lists where
  r8Y              Run length encoding of list
 >   lQ            With the first len(input) removed
                   is nonempty

入力のターンよりも1つ多くの動きがあるはずです。それぞれの動きは異なる方向にあるため、ランレングスエンコーディングは入力よりも長くする必要があります。

訪問したポイントへのマップ:

.u+NYY0  ...
.u   Y0   Reduce the following function over
          the list of steps, starting at 0.
          Return all intermediates.
  +NY     Add the new step to the current position.

自己交差しないフィルター:

f{I ...
f     Filter on
  I   Invariant under
 {    Deduplication

Tこれが成功する最初のものを見つけます:f

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