三角マンハッタン距離


26

通常のグリッドのマンハッタン距離は、あるセルから別のセルに到達するために必要な直交ステップの数です。直交ステップは、グリッドセルの端を通るステップです(コーナーとは対照的に、チェビシェフ距離を与えます)。

他のグリッド、たとえば三角形のグリッドで同様の距離を定義できます。次のインデックススキームを使用して、グリッド内の個々のセルをアドレス指定できます。各セルにはx,yペアが含まれています。

    ____________________________________...
   /\      /\      /\      /\      /\
  /  \ 1,0/  \ 3,0/  \ 5,0/  \ 7,0/  \
 / 0,0\  / 2,0\  / 4,0\  / 6,0\  / 8,0\
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,1/  \ 2,1/  \ 4,1/  \ 6,1/  \ 8,1/
  \  / 1,1\  / 3,1\  / 5,1\  / 7,1\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  /  \ 1,2/  \ 3,2/  \ 5,2/  \ 7,2/  \
 / 0,2\  / 2,2\  / 4,2\  / 6,2\  / 8,2\  
/______\/______\/______\/______\/______\...
\      /\      /\      /\      /\      /
 \ 0,3/  \ 2,3/  \ 4,3/  \ 6,3/  \ 8,3/
  \  / 1,3\  / 3,3\  / 5,3\  / 7,3\  /
   \/______\/______\/______\/______\/___...
   /\      /\      /\      /\      /\
  .  .    .  .    .  .    .  .    .  .
 .    .  .    .  .    .  .    .  .    .

ここで、このグリッドのマンハッタン距離は、1つのセルから別のセルに到達するためのエッジをまたぐ最小ステップ数です。したがって、3,1から2,14,1またはに移動できますが3,2、他の三角形には移動できません。これらの三角形はエッジではなく交差ポイントになるためです。

たとえば、から2,1までの距離5,24です。通常、最短経路は一意ではありませんが、4つのステップで距離を設定する1つの方法は次のとおりです。

2,1 --> 3,1 --> 3,2 --> 4,2 --> 5,2

チャレンジ

2つの座標ペアを指定し、上記のアドレス指定スキームから、それらの間のマンハッタン距離を返します。x1,y1x2,y2

4つすべての入力は、それぞれが128未満の非負の整数であると想定できます。任意の順序で任意にグループ化できます(4つの個別の引数、4つの整数のリスト、2つの整数のペア、2x2マトリックス、.. 。)。

プログラムまたは関数を作成し、入力を受け取って出力を提供する標準的な方法を使用できます。

任意のプログラミング言語を使用できますが、これらの抜け穴はデフォルトでは禁止されています。

これはであるため、バイト単位で測定される最短の有効な回答が勝ちます。

テストケース

各テストケースはとして与えられます。x1,y1 x2,y2 => result

1,2 1,2 => 0
0,1 1,1 => 1
1,0 1,1 => 3
2,1 5,2 => 4
0,0 0,127 => 253
0,0 127,0 => 127
0,0 127,127 => 254
0,127 127,0 => 254
0,127 127,127 => 127
127,0 127,127 => 255
75,7 69,2 => 11
47,58 36,79 => 42
77,9 111,23 => 48
123,100 111,60 => 80
120,23 55,41 => 83
28,20 91,68 => 111
85,107 69,46 => 123
16,25 100,100 => 159
62,85 22,5 => 160
92,26 59,113 => 174
62,22 35,125 => 206

正味の負の評価を受けた抜け穴は、公式の抜け穴に含まれますか?
DavidC

@DavidCいいえ。抜け穴の質問から:「[...] +5以上であり、下降投票の少なくとも2倍の投票数を持つ回答に記述された抜け穴は、コミュニティに受け入れられないとみなされる可能性があります。 "
マーティンエンダー

デフォルトで0から始まる5番目の入力(結果)を取得できますか?それから、答えに追加する必要はありません(a,b,x,y)->c(a,b,x,y,0)c4つの引数と05番目の引数で区切られたメソッドを呼び出す)。
ケビンCruijssen

3
@KevinCruijssenごめんなさい。追加の固定引数は少し簡単に悪用できます(特別なケースとして0を許可するのは奇妙に思えます)。
マーティンエンダー

@MartinEnder OK、そう思いましたが、尋ねることを決して傷つけることはできません。その場合、私の190バイトの答えは残ります。1年前に半分に回答したにもかかわらず、1つのテストケースが失敗していました。ちょうど今質問に再び出くわし、私の答えのバグを修正することができました。
ケビンCruijssen

回答:


7

JavaScript(ES6)、84 78バイト

Neilのおかげで6バイト節約

(a,b,c,d,x=a>c?a-c:c-a,y=b>d?b-d:d-b,z=x>y?x:y)=>y+z+(x+z&1?a+b+(b>d)&1||-1:0)

テストケース

初期再帰ソリューション、100 88 81

ETHproductionsのおかげで12バイトを節約Neilのおかげで7バイトを節約

f=(a,b,c,d,e=b==d|a+b+(b>d)&1)=>a-c|b-d&&f(e?a+1-2*(a>c):a,e?b:b+1-2*(b>d),c,d)+1

使い方

基本的に現在のバージョンに適用されますが、以下の説明では初期バージョンをより具体的に参照しています。

f=(a,b,c,d)=>b-d?a+b+(b>d)&1?f(a+1-2*(a>c),b,c,d)+1:f(a,b+1-2*(b>d),c,d)+1:Math.abs(a-c)

行く(X0、Y)(X1、Y)は、我々がターゲット1にソースの三角形から横方向縁部全体にすべての道を行くことができるので簡単です。この場合のマンハッタン距離は| x0-x1 |

トリッキーな部分は垂直方向のステップです。行y0から行y1に移動するには、次の2つのパラメーターを考慮する必要があります。

  • 現在の三角形の向き
  • y0y1より小さいか大きいか

三角形の向きは、x + yのパリティによって与えられます。

  • 偶数の場合、三角形は上向きです
  • 奇数の場合、三角形は下向きです

私たちは、上向きの三角形から下方(便利なときに行くことができY0 <Y1)と上向き、下向きの三角形から(便利なときY0> Y1)を。

三角形の向きをy0y1の比較と組み合わせることにより、式x + y0 +(y0> y1?1:0)が得られます。

次の行に直接到達できない場合は、最初にxを更新して正しい配置を取得する必要があります。

  • 場合、xはまだと等しくないX1場合、我々はそれをインクリメントして、我々は間違いなく、正しい方向に移動するxが未満であるX1とあれば、我々はそれをデクリメントxがより大きく、X1
  • 場合、xがすでに等しいX1を、我々は、いずれかの増分またはそれをデクリメントすることができます

テストケース


それは...非常に小さな数学演算です...しかし、n変数を完全にスキップして、各反復の結果に1を加算することはできませんか?(私は思う90文字
ETHproductions

@ETHproductions正直に言うと、私は深刻なゴルフをすることなく投稿しました。しかし、それは間違いなく最初にすることです。ありがとう!
アーナルド

1
また、私は考えるの演算子の優先順位&を行うことができます手段a+b+(b>d)&12バイト節約するために
ETHproductions

81になったと思う:f=(a,b,c,d,e=b==d|a+b+(b>d)&1)=>a-c|b-d&&f(e?a+1-2*(a>c):a,e?b:b+1-2*(b>d),c,d)+1
ニール

賢いカレーを使用して別のバイトを保存することは可能だと思います。
ニール

5

Python 2、74バイト

lambda x,y,X,Y:abs(y-Y)+max(x-X,X-x,abs(y-Y)+((x+y+X+Y)%-2)**(x^y^(Y>=y)))

1
この部分を説明してもらえます**(x^y^(Y>=y))か?
デッドポッサム

1
@DeadPossum垂直方向に距離1だけ移動すると、1回または3回移動します。パリティを見るだけでは判断できないため、y値を比較する必要があります。
-feersum

2

バッチ、99バイト

@cmd/cset/a"x=%3-%1,x*=x>>31|1,y=%4-%2,w=y>>31,y*=w|1,z=x+(y+x&1)*(-(%1+%2+w&1)|1)-y,z*=z>>31,x+y+z

説明:水平のみの動きは、絶対的なX座標の差を単純に取ります。十分に大きいxの場合、垂直方向の動きは絶対y座標の差ごとに1ステップだけかかりますが、小さいxの場合、2つのy座標の差ごとに4ステップ余分に加え、奇数の差の場合は1または3ステップかかります。これは、差ごとに2つのステップと補正係数として計算されます。修正された2つのステップと絶対差の合計の大きい方が結果になりますが、これは、修正された絶対y座標差と修正されていない絶対y座標差に加算された絶対x座標距離の大きい方として計算されます。

  • @cmd/cset/a" -コンマ区切りの式を評価し、最後の式を出力します
  • x=%3-%1,x*=x>>31|1バツ=|バツ2バツ1|
  • y=%4-%2,w=y>>31,y*=w|1w=y1>y2y=|y2y1|
  • z=x+(y+x&1)*(-(%1+%2+w&1)|1)-yc=y+バツmod212バツ1+y1+wmod2z=バツ+cy
  • z*=z>>31,x+y+z計算しますmaバツバツyc+y=バツ+ymn0バツ+cy

2

ゼリー、24バイト

⁴<³¬Ḋ;³S
SḂN*¢+ḊḤ$
ạµS»Ç

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

バツyバツY

d=|yY|+最大|バツバツ||yY|+バツ+y+バツ+Ymod2バツyYy=|yY|+最大|バツバツ||yY|+[|バツバツ|+|yY|mod2]バツ+y+Yy=最大|バツバツ|+|yY|2|yY|+[|バツバツ|+|yY|mod2]Yy+バツ+y

¢=Yy+バツ+y

L=[|バツバツ||yY|]LfLf

L=[ab]a+bmod2¢2b


2

ラケット/スキーム、214バイト

(define(f x y X Y)(let m((p x)(q y)(c 0))
(let((k(+ c 1))(d(- Y q)))
(cond((= 0(- X p)d)c)
((and(> d 0)(even?(+ p q)))(m p(+ q 1)k))
((and(< d 0)(odd?(+ p q)))(m p(- q 1)k))
((< p X)(m(+ p 1)q k))
(else(m(- p 1)q k))))))

2

05AB1E、24バイト

バツ1バツ2y1y2

ÆÄ`©I˜OÉ(IøнOIθD{Q+m+M®+

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

壊す

ÆÄ`©I〜OÉ(IøнOIθD{Q + m +M®+完全プログラム。Iは評価された入力を表します。
ÆÄ減算によりペアを減らし、絶対値を取得します。
  `©別々にスタックにダンプし、2番目を保存する
                            1つ、| y1-y2 | レジスタC
    I〜O平坦化された入力の合計をスタックにプッシュします。
       É(そのパリティを取り、それを否定します。
         IøнPush [x1、y1]。
            O x1 + y1(それらを合計)してください。
             IθD{Q次に、2番目のペアがソートされているかどうかを確認します(y1≤y2)。
                  +そして、それをx1 + y1と合計します。
                   mべき乗。パリティを結果より上にプッシュします。
                    +そして、それに2番目の絶対差を加えます。
                     M®+結果として、スタックの最大数をプッシュします
                            さらに、レジスタCに格納されている値

100%確信はありませんが、©を変更してDを削除することはできません®か?現在TIOにあるケースで機能するようですが、すべてのケースで同じパスをたどるかどうかはわかりません。
ケビンクルーッセン

1
@KevinCruijssen EDIT:いいえ、これはMの動作に影響するためです。失敗し[[0, 127], [0, 0]]ます。
Mr Xcoder

2

パイソン274の 72 71バイト

lambda c,a,d,b:abs(a-b)+abs(a+(-c-a)/2-b-(-d-b)/2)+abs((c+a)/2-(d+b)/2)

オンラインでお試しください!リンクにはテストケースが含まれます。編集:@JoKingのおかげで2バイト保存されました。@ Mr.Xcoderのおかげでさらにバイトを節約できました。この質問で見つけた次の式に基づいて:

|ab|+|aaj2bbj2|+|aj+12bj+12|

12090

|ab|+|aaj+12bbj+12|+|aj2bj2|

aj+12=aj2


改行を削除することでワンライナーにすることができます
ジョーキング

1
lambda c,a,d,b:abs(a-b)+abs(a+-(c+a)/2-b--(d+b)/2)+abs((c+a)/2-(d+b)/2)3バイトを節約する必要があります。
Mr Xcoder

1

Pyth31 28バイト

バツ1バツ2y1y2

+eKaMQg#hK+eK^%ssQ_2+shCQSIe

ここで試してみてください!またはテストスイートをお試しください!

壊す

+ eKaMQg#hK + eK ^%ssQ_2xxFhCQSIe完全なプログラム。Q = eval(input())。
  KaMQ差[| x1-x2 |、| y1-y2 |]をKに保存します。
 e後者(| y1-y2 |)を取得します。
+ g#そして、以下の最大値に追加します。
        hK-Kの頭(| x1-x2 |)
          +-そして追加の結果:
           eK Kの終わり(| y1-y2 |)。
             ^-べき乗の結果:
              %ssQ_2平坦化されたQの合計、モジュロ-2。
                                        x1 + x2 + y1 + y2が奇数の場合は-1、それ以外の場合は0を返します。
                    xxFhCQSIe-この式の結果により:
                       hCQ Qを転置し、頭部(x1、y1)を取得します。
                     xFビット単位のXORによる縮小。
                          SIeリスト[y1、y2]がソートされているかどうかを確認します。
                    xその後、ブール(0/1)による結果をxor。

1

05AB1E、16バイト

バツ1バツ2y1y2

+D(‚2÷Æ`²Æ©+®)ÄO

オンラインでお試しください!またはテストスイートをお試しください! Kevin Cruijssenの好意により、わずかに変更されたバージョンのコードを(®ではなく²使用します


いい答えだ!ゴルフには関係ありませんが、変更©+®するDŠ+とテストスイートのセットアップが簡単になります。;)ここにそのテストスイートがあり、すべてのテストケースは実際に成功しています(厄介なヘッダーは無視してください; p)。
ケビンCruijssen

@KevinCruijssen私は代替バージョンとしてということがあったが、私がテストスイートを書くことができますように私には発生しなかった...おかげで、私はそれを追加します
ミスターXcoder

1
@KevinCruijssen私はもう2バイト(非常に明白な...!)バイトを使い果たし、テストスイートの互換性をさらに破ることに成功したので、そのままにしておきました:Pところで編集してくれてありがとう。
ミスターXcoder


1

ジャワ8、157の 190 188 144 142 141 127バイト

(a,b,x,y)->{int r=0,c=1,z=1;for(;(c|z)!=0;r--){c=x-a;z=y-b;if((z<0?-z:z)<(c<0?-c:c)|a%2!=b%2?z<0:z>0)b+=z<0?-1:1;else a+=c<0?-1:1;}return~r;}

バグ修正のため、+ 33バイト(157→190)。
-44バイト(188→144)再帰メソッドを単一のループメソッドに変換します。@ceilingcatの
おかげで-14バイト。

説明:

ここで試してみてください。

(a,b,x,y)->{          // Method with four integers as parameter and integer return-type
                      // (a=x1; b=y1; x=x2; y=y2)
  int r=0,            //  Result-integer `r`, starting at 0
      c=1,z=1;        //  Temp integers for the differences, starting at 1 for now
  for(;(c|z)!=0;      //  Loop until both differences are 0
      r--){           //    After every iteration: decrease the result `r` by 1
    c=x-a;            //   Set `c` to x2 minus x1
    z=y-b;            //   Set `z` to y2 minus y1
    if(z*Z            //   If the absolute difference between y2 and y1
       <c*c)          //   is smaller than the absolute difference between x2 and x1
       |a%2!=b%2?     //   OR if the triangle at the current location is facing downwards
         z<0          //       and we have to go upwards,
        :z>0)         //      or it's facing upwards and we have to go downwards
      b+=z<0?-1:1;    //    In/decrease y1 by 1 depending on where we have to go
    else              //   Else:
     a+=c<0?-1:1;}    //    In/decrease x1 by 1 depending on where we have to go
  return~r;           //  Return `-r-1` as result

1
提案z*z<c*cの代わりに(z<0?-z:z)<(c<0?-c:c)
ceilingcat

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