最大の凸多角形の面積を見つける


28

整数座標のリストが与えられたら、リストから構築できる最大の凸多角形の面積を見つけます-

  • すべての頂点がリストにあります
  • リストの要素はポリゴン内に含まれていません。

例:

(0、0)(8、0)(0、1)(3、1)(7、1)(1、2)(5、2)(9、2)(2、3)(5、3) (7、3)(3、4)(5、5)(11、5)

視覚化:

o       o
o  o   o
 o   o   o
  o  o o
   o
     o     o

これから作成できる最大の凸多角形は次のとおりです。

o     
o  o  
 o   o
  o  o
   o
     o

面積は12です。


任意の適切な形式で座標のリストを取得し、小数点以下2桁以上に丸められた最大の凸多角形の領域を(選択した言語に適切な方法で)出力する必要があります。

さらに、ポイントのすべてのサブセットを単純にブルートフォースするのではなく、何らかのアルゴリズムを使用する必要があります。これを強制するには、プログラムは最新のPCで1分以内に50個の頂点のリストを解決する必要があります。

バイト単位の最短コードが優先されます。


最悪の場合の高速アルゴリズムを知っていますか?
-xnor

3
100個の頂点に時間制限を適用する場合は、少なくとも1つのテストケース(理想的には複数、たとえば100個の頂点すべてがソリューションの一部である場合、99個が10個、10個のみが1個)を含める必要があります。
マーティンエンダー

@MartinBüttner残念なことに、私は実際に動作する実装を持っていないため、このテストケースを生成できません。問題は
ややこしい

@xnorいくつかの例がここにあります
orlp

「小数点以下2桁以上に丸められます」?
DavidC

回答:


12

Javascript ES6、738バイト

((V,C,L,r,k,n,A,G,F,e,i,j,q)=>p=>{p=p.map((p,i)=>({i:i,x:p[0],y:p[1]}));A=(f,p,a,b,v,i)=>{for(i=p[n],v=V(a,b);i--;)if(f(v,V(a,p[i])))return 1};G=(p,i,a)=>{for(i=p[n]-1,a=C(p[i],p[0]);i--;)a+=C(p[i],p[i+1]);if((a/=2)>r)r=a};F=(p,s,l,f,a,b,v)=>(l=s[n],f=s[0],a=s[l-2],b=s[l-1],e[a.i][b.i]||A((a,b)=>C(a,b)?0:a.x<0==b.x<0&&a.y<0==b.y<0&&L(a)>L(b),p,a,b)?0:(p=(v=V(a,b),p[k](x=>C(v,V(a,x))>=0)),A((a,b)=>C(a,b)>0,p,b,f)?0:(p.map(q=>F(p[k](r=>q!==r),[...s,q])),s[2]&&!p[n]&&!e[b.i][f.i]?G(s):0)));e=p.map(x=>p.map(y=>x===y));for(i=p[n];i--;){for(j=i;j--;){q=p[k]((p,x)=>x-i&&x-j);F(q,[p[i],p[j]]);F(q,[p[j],p[i]]);e[i][j]=e[j][i]=1}}console.log(r)})((a,b)=>({x:b.x-a.x,y:b.y-a.y}),(a,b)=>a.x*b.y-a.y*b.x,v=>v.x*v.x+v.y*v.y,0,'filter','length')

以下は、ほとんどのブラウザーとノードで調整せずに動作するES5以前のバージョンです。827 バイト

eval("(%V,C,L,r,k,n,A,G,F,e,i,j,q){@%p){p=p.map(%p,i){@{i:i,x:p[0],y:p[1]}});A=%f,p,a,b,v,i){for(i=p[n],v=V(a,b);i--;)if(f(v,V(a,p[i])))@1};G=%p,i,a){for(i=p[n]-1,a=C(p[i],p[0]);i--;)a+=C(p[i],p[i+1]);if((a/=2)>r)r=a};F=%p,s,l,f,a,b,v){@(l=s[n],f=s[0],a=s[l-2],b=s[l-1],e[a.i][b.i]||A(%a,b){@C(a,b)!=0?0:a.x<0==b.x<0&&a.y<0==b.y<0&&L(a)>L(b)},p,a,b)?0:(p=(v=V(a,b),p[k](%x){@C(v,V(a,x))>=0})),A(%a,b){@C(a,b)>0},p,b,f)?0:(p.forEach(%q){@F(p[k](%r){@q!==r}),s.concat([q]))}),s[2]&&p[n]==0&&!e[b.i][f.i]?G(s):0)))};e=p.map(%x,i){@p.map(%y,j){@i==j})});for(i=p[n];i--;){for(j=i;j--;){q=p[k](%p,x){@x!=i&&x!=j});F(q,[p[i],p[j]]);F(q,[p[j],p[i]]);e[i][j]=e[j][i]=1}}console.log(r)}})(%a,b){@{x:b.x-a.x,y:b.y-a.y}},%a,b){@a.x*b.y-a.y*b.x},%v){@v.x*v.x+v.y*v.y},0,'filter','length')".replace(/%/g,'function(').replace(/@/g,'return '))

コードは匿名関数を返します。パラメータとして、のようなポイントの配列を取ります[[0,1],[2,3],[4,5]]。それを使用するにはvar f=、その前に配置するか、コマンドラインから使用する場合は(process.argv[2].replace(/ /g,'').slice(1,-1).split(')(').map((x)=>x.split(',')))、最後に追加して、次のように呼び出しますnode convpol.js '(1,2)(3,4)(5,6)'

挑戦してくれてありがとう!リファレンス実装がないため、これが正しいことを証明することはできませんが、少なくともポイントリストの順列については一貫しています。デバッグコードが無効になっていてもバージョンが指数関数的な時間の増加とともに遅すぎるので、私はこれがうまくいくとは思わなかった。とにかくゴルフをすることにし、私のマシンで50ポイントで2秒未満に落ちたことを見て喜んでいた。1分で約130ポイントを計算できます。

このアルゴリズムはGraham scanに似ていますが、どこでも空の凸包を検索する必要がある点が異なります。

説明

アルゴリズムの仕組みの概要を以下に示します。このアルゴリズムの要点は、ポイントを囲まない反時計回りの凸ループを検索することです。手順は次のようなものです。

  1. ポイントのペアから始め、他のすべてのポイントのリストを作成します。
  2. 現在のポイントのペアがリスト内の任意のポイントを正確に通過する場合、停止します。
  3. 現在のペアの時計回りのすべてのポイントをフィルターで除外します。ポリゴンが凹面になるためです。
  4. 残っているすべてのポイントについて、次の操作を行います。
    1. このポイントからチェーンの最初のポイントまでのラインが反時計回りにポイントを通過または囲む場合、ポリゴンはポイントを囲むため、このポイントをスキップします。
    2. このポイントをチェーンに追加し、現在のチェーンとポイントのリストを使用して手順1から再帰します。
  5. ポイントが残っておらず、チェーンに少なくとも3つのポイントがある場合、これは有効な凸多角形です。これらのポリゴンの最大面積を覚えておいてください。

また、最適化として、チェインの最初のペアをチェック済みとして記録します。したがって、このペアを持つ最大のポリゴンがすでに見つかっているため、チェイン内のこのペアを見た後の検索はすぐに検索を停止できます。

このアルゴリズムはポリゴンを2回検出することはありません。これを実験的に検証しました。


2
+1、これは驚くべき答えです。===and !====and !=で置き換えることができるかもしれませんが、あなたのコードを理解しないと確信できませんでした
...-jrich

1
ありがとう!これらの特定の===と!==はオブジェクトを比較しているので、残念ながらありません。以前はインデックスを比較していましたが、(x,i)=>p.i==i(13文字)はx=>p===x最適化後でも(8文字)よりもかなり長いです。
ricochet1k

2
あなたのための説明があります@Lembik
ricochet1k

1
リンクされたSO質問のコメントで言及されているO(n ^ 3)レコードを破ったようです!

1
申し分なく、これがO(n ^ 3)未満で実行される可能性があるとは思わないところまで進んでいます。私はアルゴリズムの複雑さに非常に新しいです。
ricochet1k
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.