幸せなエンダー問題


32

ハッピーエンドの問題は、(実際の定理)の状態

一般的な位置にある平面内の5つのポイントのセットには、凸状の四角形の頂点を形成する4つのポイントのサブセットがあります。

この問題は最初に問題に取り組んだ2人の数学者、エステルクラインとジョージセケレスが婚約し、その後結婚したときに、ポール・エルデスによってそのように命名されました。

明確化:

  • ここでの一般的な位置とは、3つのポイントが同一線上にないことを意味します。
  • 4つの頂点によって形成される四角形は、ポイントの順序に関係なく、常に交差していないと見なされます。例えば、4点所与[1 1][1 2][2 1][2 2]意図四辺形は、正方形ではなく、ボウタイです。

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

  • 内角が180度を超えない場合、交差しない四角形は凸状になります。または同等に両方の対角線が四角形の内側にある場合。

チャレンジ

正の整数座標を持つ5つのポイントが与えられた場合、凸四辺形を形成するこれらのポイントのうち4つを出力します。

ルール

複数のソリューションがある場合(つまり、4ポイントのセットが複数ある場合)、それらの1つまたはすべてを一貫して出力することを選択できます。

入力形式と出力形式は通常どおり柔軟です(配列、リスト、リストのリスト、適切な区切り文字のある文字列など)。

コードゴルフ、最少バイトが勝ちます。

テストケース

  1. 入力:

    [6 8] [1 10] [6 6] [5 9] [8 10]
    

    可能な出力は1つだけです。

    [6 8] [1 10] [6 6] [5 9]
    
  2. 入力:

    [3 8] [7 5] [6 9] [7 8] [5 1]
    

    5つの解決策があります。

    [3 8] [7 5] [6 9] [7 8]
    [3 8] [7 5] [6 9] [5 1]
    [3 8] [7 5] [7 8] [5 1]
    [3 8] [6 9] [7 8] [5 1]
    [7 5] [6 9] [7 8] [5 1]
    
  3. 入力:

    [4 8] [1 9] [9 9] [10 2] [1 6]
    

    3つの解決策があります。

    [4 8] [1 9] [10 2] [1 6]
    [4 8] [9 9] [10 2] [1 6]
    [1 9] [9 9] [10 2] [1 6]
    

    説明のために、この場合の3つのソリューションを次に示します。

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


14
私は、そこに表明された肯定的な感情を持つマーティンからの答えを期待しています。
エレンディアスターマン

1
ハッピーエンドの問題は、ハッピーエンダーの問題と混同しないでください。エンダーの問題は、軍の新兵が彼らがプレイしているシミュレーションが本物であることを発見するの防ぐ方法を見つけることです
user253751

回答:


24

CJam、37 34 32バイト

{e!Wf<{2*3ew{)f.-~W%.*:-V>},!}=}

:-V十分に幸せかどうかはわかりませんが、K Zhangが指摘するように=}、最後にあります。:)

重複の削除はより高価になるため、これは1つのソリューションのみを出力します。

ここでテストしてください。

説明

アイデアはかなり単純です。可能なすべての四辺形(ポイントのすべての順序を含む)を生成し、凸面のものを選択します。エッジのすべてのペアを見て、それらがすべて同じ方向に回転していることを確認することにより、凸性をテストします。

回転感覚は、ドット積から非常に簡単に得られます。四辺形の3つの連続した点を取り、1番目から2番目、1番目から3番目に線を引き、後者を前者の垂線上に投影すると...これらの3点が左に曲がるか右に曲がるか。(おそらく、この図を追加する必要があります。)この「垂直への投影」は非常に複雑に聞こえますが、実際には、2つのベクトルの一方を反転し、乗算ではなく加算後に成分を減算します。ここにコードがあります...

e!       e# Generate all permutations of the five input points.
Wf<      e# Discard the fifth point in each permutations, giving all
         e# possible quadrilaterals.
{        e# Select the first for which this block gives a truthy result...
  2*     e#   Double the list of points, so that it includes each cyclically
         e#   adjacent set of three points.
  3ew    e#   Get all sublists of length 3, i.e. all sets of three consecutive
         e#   points (with two duplicates).
  {      e#   Filter these sets of three points...
    )    e#     Pull off the last point.
    f.-  e#     Subtract it from the other two, giving vectors from it to
         e#     to those.
    ~    e#     Unwrap the array dumping both vectors on the stack.
    W%   e#     Reverse one of them.
    .*   e#     Element-wise multiplication.
    :-   e#     Subtract the second element from the first. This completes
         e#     the projection.
    V>   e#     Check whether it's greater than 0. This is *false* for right-
         e#     turning sets of three points.
  },     e#   If all corners are right-turning, this will result
         e#   in an empty array.
  !      e#   Logical NOT - hence, only quadrilaterals where all corners
         e#   are right-turning give something truthy.
}=

2
確かに、幸せなアヒル!
ルイスメンドー

1
@LuisMendo最後の2人のキャラクターはスマイリーのように見えると思う=}
Kチャン

!}ウィンクと見なされる可能性もあります
ジェザモン

2
CodeGolfのジョンスキートは...これは素晴らしいです
アレックス・カールセン

8

MATLAB、67バイト

I=input('');for k=~eye(5);if nnz(convhull(I(k,:)))>4;I(k,:),end;end

入力は、列がそれぞれXとYである2Dマトリックスの形式です。

[6 8; 1 10; 6 6; 5 9; 8 10]
[3 8; 7 5; 6 9; 7 8; 5 1]
[4 8; 1 9; 9 9; 10 2; 1 6]

凸四辺形を作成する4点のすべてのセットは、同じ形式で表示されます。

Octaveで動作するように少し変更されたデモを次に示します

説明

このソリューションは、入力の4ポイントのすべてのサブセットを取得します(順序は関係ありません)。これを行うには、恒等行列を作成して否定します~eye(5)。この行列の列をループし、k(ループインデックス)は、4つのポイントのどれを考慮するかを指定する論理配列です。次に、これを使用して、入力からこれらの4つのXYポイントを取得します(I(k,:))。

次に、これらの4点の凸包を計算しconvhullます()。の出力はconvhull、凸包を構成する点に対応する入力のインデックスです(最初のインデックスが複製されてハルを閉じます)。

凸四角形の場合、4つのポイントはすべて同じポイントの凸包の一部になります(nnz(convhull(points)) > 4)。これが事実であることを検出した場合、この特定の反復に使用されたポイントを表示します。


4

Javascript(ES6)、306 293 283バイト

c=(v,w,x)=>(w[0]-v[0])*(w[1]-x[1])-(w[1]-v[1])*(w[0]-x[0])>0?1:0
i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])
j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}
f=(v)=>(r=[],k(...v),r)

説明

この関数cは、ポリゴンの3つの隣接するポイント間のベクトルの外積を計算し、正の場合は1を返し、それ以外の場合は0を返します(注:点が同一線上にないため、外積はゼロになりません)。

j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}

機能kj、入力配列のすべての巡回置換(順序を逆に無視する)を生成します。

i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])

関数 'i'は、各巡回置換に対して呼び出されc、隣接する座標の4つのトリプレットのそれぞれの関数の合計を計算します。すべての外積に同じ符号がある場合、それらはすべて0または1であり、合計が0(モジュロ4)であり、多角形は凹面であり、出力配列にプッシュされます。トリプレットの符号が異なる場合、合計はゼロ以外(モジュロ4)になり、多角形は凸になります。

f=(v)=>(r=[],k(...v),r)

この関数fは、出力配列を初期化し、出力を返す前に上記の関数を呼び出すために使用されます。

テスト

c=(v,w,x)=>(w[0]-v[0])*(w[1]-x[1])-(w[1]-v[1])*(w[0]-x[0])>0?1:0
i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])
j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}
f=(v)=>(r=[],k(...v),r)

tests = [
  [[6,8],[1,10],[6,6],[5,9],[8,10]],
  [[3,8],[7,5],[6,9],[7,8],[5,1]],
  [[4,8],[1,9],[9,9],[10,2],[1,6]]
];

tests.forEach(
  (test,i)=>{
    console.log( "Test " + (i+1) );
    f(test).forEach(
      (x)=>console.log( "  " + x.map((e)=>"("+e[0]+","+e[1]+")").join(','))
    );
  }
);

編集

また、元のバージョンを使用し、最初の2行を次のように変更して、同一直線上の点を処理できます。

t=(a,b,c)=>Math.sign((b[0]-a[0])*(b[1]-c[1])-(b[1]-a[1])*(b[0]-c[0]))
p=(a,b,c,d)=>[t(a,b,c),t(b,c,d),t(c,d,a),t(d,a,b)].filter(x=>x).reduce((p,c,i,a)=>p&c==a[0],1)
q=(a,m,n,o)=>[a[0],a[m],a[n],a[o]]
f=(a)=>{r=[];for(i=0;i<5;i++){b=a.slice();b.splice(i,1);r.push(q(b,1,2,3));r.push(q(b,1,3,2));r.push(q(b,2,1,3))}return r.filter((a)=>p(...a))}

ただし、そのケースは質問で明確に除外されているため、余分な文字は必要ありません。


3

Mathematica 105 96バイト

Select[#~Subsets~{4},f@#&]&(5)点のリストから、を満たす4点のサブセットを選択しfます。

f満たされたときにセットにおける4点の各点、上にあるRegionBoundaryConvexHull4点。

f@p_:=Apply[And,RegionBoundary@ConvexHullMesh@p~RegionMember~#&/@p];
Select[#~Subsets~{4},f@#&]&

テストケース

1. {{6、8}、{1、10}、{6、6}、{5、9}、{8、10}}のサブセット(それぞれ4点)の5つの凸包を見てみましょう。

Select[#~Subsets~{4},f@#&[{{6, 8}, {1, 10}, {6, 6}, {5, 9}, {8, 10}}]

{{{6、8}、{1、10}、{6、6}、{5、9}}}


{{6、8}、{1、10}、{6、6}、{5、9}}が唯一の解決策です。4つのポイントはそれぞれ、(同じ4ポイントの)凸包の頂点として機能します。

溶液


{{6、8}、{1、10}、{6、6}、{8、10}}は解決策ではありません。凸包の頂点は3つだけです。{6、8}は船体内にあります。

fail1


残りのサブセットも解決策ではありません。

fail2

fail3

fail4


2. {{4、8}、{1、9}、{9、9}、{10、2}、{1、6}}には3つのソリューションがあります。

Select[#~Subsets~{4},f@#&[{{4, 8}, {1, 9}, {9, 9}, {10, 2}, {1, 6}}]

{
{{4、8}、
{1、9 }、{10、2 }、{1、6 }}、{{ 4、8}、{9、9 }、{10、2 }、{1、6 }}、
{{ 1、9}、{ 9、9}、{ 10、2}、{1、6}}
}


3. {{3、8}、{7、5}、{6、9}、{7、8}、{5、1}}には5つのソリューションがあります。

Select[#~Subsets~{4},f@#&[{{3, 8}, {7, 5}, {6, 9}, {7, 8}, {5, 1}}]

{
{{3、8}、
{7、5 }、{6、9 }、{ 7、8}}、{{ 3、8}、{7、5 }、{6、9 }、{5、1 }}、
{{ 3、8}、{7、5}、{7、8}、
{5、1 }}、{{ 3、8}、{6、9}、{7、8}、{5 、1}}、
{{ 7、5}、{6、9}、{7、8}、{5、1}
}}

5つのポイントはそれぞれ、すべてのポイントの凸包の境界上にあることに注意してください。

いずれかのポイントが削除されると、残りの4つのポイントはそれぞれ縮小された凸包の頂点になります。

sol2

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