가장 큰 볼록 다각형의 면적을 구합니다


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 개의 꼭짓점에 시간 제한을 적용하려면 적어도 하나의 테스트 사례를 포함해야합니다 (이상적으로는 몇 가지, 예를 들어 100 개의 꼭짓점이 모두 솔루션의 일부인 경우, 99 개는 10 개, 10 개는 하나임) .
Martin Ender

@ MartinBüttner 슬프게도, 실제 구현이 없기 때문에이 테스트 케이스를 생성 할 수 없습니다. 문제는 다소 까다 롭다 :)
orlp

@xnor 여기에 몇 가지 예가 있습니다 .
orlp

"소수점 뒤에 2 자리 이상으로 반올림"?
DavidC

답변:


12

자바 스크립트 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
+1, 이것은 놀라운 답변입니다. 당신은 대체 할 수 있습니다 ===!====!=, 그러나 나는 ... 당신의 코드를 이해하지 않고 확신 할 수
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.