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')
Đây là phiên bản ES5 trở xuống nên hoạt động trong hầu hết các trình duyệt và nút mà không cần điều chỉnh: 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 '))
Mã trả về một hàm ẩn danh. Là một tham số, nó cần một mảng các điểm, như [[0,1],[2,3],[4,5]]
. Để sử dụng nó, bạn có thể đặt var f=
trước nó hoặc nếu bạn muốn sử dụng nó từ dòng lệnh, thêm (process.argv[2].replace(/ /g,'').slice(1,-1).split(')(').map((x)=>x.split(',')))
vào cuối và gọi nó như thế nàonode convpol.js '(1,2)(3,4)(5,6)'
Cảm ơn các thử thách! Vì không có triển khai tham chiếu, tôi không thể chứng minh điều này là đúng, nhưng ít nhất nó phù hợp với hoán vị của danh sách điểm. Tôi gần như không nghĩ rằng điều này sẽ hoạt động, vì các phiên bản có mã gỡ lỗi, thậm chí bị vô hiệu hóa, quá chậm với thời gian tăng theo cấp số nhân. Tôi đã quyết định chơi golf bằng mọi cách, và rất vui khi thấy nó giảm xuống dưới 2 giây cho 50 điểm trên máy của tôi. Nó có thể tính toán khoảng 130 điểm trong 1 phút.
Thuật toán tương tự như quét Graham , ngoại trừ việc nó phải tìm kiếm các vỏ lồi rỗng ở khắp mọi nơi.
Giải trình
Đây là một tổng quan cấp cao về cách thức hoạt động của thuật toán. Phần cốt lõi của thuật toán này chỉ là tìm kiếm các vòng lồi ngược chiều kim đồng hồ không kèm theo một điểm. Thủ tục là như thế này:
- Bắt đầu với một cặp điểm và danh sách tất cả các điểm khác.
- Nếu cặp điểm hiện tại đi chính xác qua bất kỳ điểm nào trong danh sách, hãy dừng lại.
- Lọc ra tất cả các điểm theo chiều kim đồng hồ của cặp hiện tại, vì chúng sẽ làm cho đa giác lõm.
- Đối với tất cả các điểm còn lại, hãy làm như sau:
- Nếu một đường thẳng từ điểm này đến điểm đầu tiên của chuỗi đi qua hoặc bao quanh bất kỳ điểm nào ngược chiều kim đồng hồ, hãy bỏ qua điểm này, vì bất kỳ đa giác nào cũng sẽ bao quanh điểm đó.
- Thêm điểm này vào chuỗi, lặp lại từ bước 1 với chuỗi hiện tại và danh sách các điểm.
- Nếu không còn điểm nào và chuỗi có ít nhất 3 điểm thì đây là đa giác lồi hợp lệ. Hãy nhớ diện tích lớn nhất của các đa giác này.
Ngoài ra, để tối ưu hóa, chúng tôi ghi lại cặp chuỗi ban đầu khi được kiểm tra, do đó, bất kỳ tìm kiếm nào sau khi thấy cặp này ở bất kỳ đâu trong chuỗi đều có thể ngừng tìm kiếm, vì đã tìm thấy đa giác lớn nhất với cặp này.
Thuật toán này sẽ không bao giờ tìm thấy một đa giác hai lần và tôi đã xác minh bằng thực nghiệm điều này.