Javascript ES6, 738 bytes
((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')
Aquí hay una versión ES5 o menos que debería funcionar en la mayoría de los navegadores y nodos sin ajustar: 827 bytes
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 '))
El código devuelve una función anónima. Como parámetro, toma una serie de puntos, como [[0,1],[2,3],[4,5]]
. Para usarlo, puede colocarlo var f=
antes, o si desea usarlo desde la línea de comando, agregar (process.argv[2].replace(/ /g,'').slice(1,-1).split(')(').map((x)=>x.split(',')))
al final y llamarlo comonode convpol.js '(1,2)(3,4)(5,6)'
Gracias por el reto! Como no hay implementación de referencia, no puedo probar que esto sea correcto, pero es consistente al menos para las permutaciones de la lista de puntos. Casi no pensé que esto iba a funcionar, ya que las versiones con código de depuración, incluso deshabilitadas, eran demasiado lentas con un aumento exponencial del tiempo. Decidí jugar golf de todos modos, y me complació ver que se redujo a menos de 2 segundos por 50 puntos en mi máquina. Puede calcular aproximadamente 130 puntos en 1 minuto.
El algoritmo es similar al escaneo de Graham , excepto que tiene que buscar cascos convexos vacíos en todas partes.
Explicación
Aquí hay una descripción general de alto nivel de cómo funciona el algoritmo. La esencia de este algoritmo es solo buscar bucles convexos en sentido antihorario que no encierren un punto. El procedimiento es algo como esto:
- Comience con un par de puntos y una lista de todos los demás puntos.
- Si el par de puntos actual atraviesa exactamente cualquier punto de la lista, deténgase.
- Filtre todos los puntos en el sentido de las agujas del reloj del par actual, ya que harían cóncavo al polígono.
- Para todos los puntos restantes, haga lo siguiente:
- Si una línea desde este punto hasta el primer punto de la cadena atraviesa o encierra algún punto en sentido antihorario, omita este punto, ya que cualquier polígono encerraría el punto.
- Agregue este punto a la cadena, repita desde el paso 1 con la cadena actual y la lista de puntos.
- Si no quedaban puntos, y la cadena tiene al menos 3 puntos, este es un polígono convexo válido. Recuerde el área más grande de estos polígonos.
Además, como optimización, registramos el par inicial de la cadena como verificado, por lo que cualquier búsqueda posterior al ver este par en cualquier parte de la cadena puede dejar de buscar inmediatamente, ya que el polígono más grande con este par ya se ha encontrado.
Este algoritmo nunca debería encontrar un polígono dos veces, y lo he verificado experimentalmente.