Javascript ES6, 738 byte
((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')
Ecco una versione ES5 o inferiore che dovrebbe funzionare nella maggior parte dei browser e dei nodi senza modifiche: 827 byte
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 '))
Il codice restituisce una funzione anonima. Come parametro, prende una serie di punti, come [[0,1],[2,3],[4,5]]. Per usarlo puoi posizionarlo var f=prima di esso, o se vuoi usarlo dalla riga di comando, aggiungi (process.argv[2].replace(/ /g,'').slice(1,-1).split(')(').map((x)=>x.split(',')))alla fine e chiamalo comenode convpol.js '(1,2)(3,4)(5,6)'
Grazie per la sfida! Poiché non esiste un'implementazione di riferimento, non posso dimostrare che ciò sia corretto, ma è coerente almeno per le permutazioni dell'elenco punti. Quasi non pensavo che avrebbe funzionato, poiché le versioni con codice di debug, anche disabilitate, erano troppo lente con un aumento esponenziale del tempo. Ho deciso comunque di giocare a golf, e sono stato contento di vedere che è sceso a meno di 2 secondi per 50 punti sulla mia macchina. Può calcolare circa 130 punti in 1 minuto.
L'algoritmo è simile alla scansione di Graham , tranne per il fatto che deve cercare ovunque scafi convessi vuoti.
Spiegazione
Ecco una panoramica di alto livello su come funziona l'algoritmo. La sostanza di questo algoritmo è solo la ricerca di anelli convessi in senso antiorario che non racchiudano un punto. La procedura è simile a questa:
- Inizia con una coppia di punti e un elenco di tutti gli altri punti.
- Se la coppia di punti corrente passa esattamente attraverso qualsiasi punto dell'elenco, fermati.
- Filtra tutti i punti in senso orario della coppia corrente, poiché renderebbero il poligono concavo.
- Per tutti i punti rimasti, procedi come segue:
- Se una linea da questo punto al primo punto della catena attraversa o racchiude tutti i punti in senso antiorario, salta questo punto, poiché qualsiasi poligono lo racchiuderebbe.
- Aggiungi questo punto alla catena, riprendi dal passaggio 1 con la catena corrente e l'elenco dei punti.
- Se non sono rimasti punti e la catena ha almeno 3 punti, questo è un poligono convesso valido. Ricorda la più grande area di questi poligoni.
Inoltre, come ottimizzazione, registriamo la coppia iniziale della catena come selezionata, quindi eventuali ricerche successive vedendo questa coppia in qualsiasi punto della catena possono immediatamente interrompere la ricerca, poiché il poligono più grande con questa coppia è già stato trovato.
Questo algoritmo non dovrebbe mai trovare un poligono due volte e l'ho verificato sperimentalmente.