Description
Input
Output
折半搜索,用散列表记录从原点出发,用了S(状压表示)这几种边(令|S|*2-1<=n),到达(x,y)的最大面积。
#include<cstdio> #include<cmath> #include<algorithm> int ps[301][8][2],pp[301],r[10],n,ed[10],st=0,ans; #define cal(w,x,y,a,b,s) dfs(w,x+(a),y+(b),s+x*(b)-y*(a)) const int P=1844677; int h[P][4],ht=0,ds[32]; void maxs(int&a,int b){if(a<b)a=b;} void mins(int&a,int b){if(a>b)a=b;} void ins(int st,int x,int y,int s){ int X,w,st2=(1<<n)-1-st; if(ds[st2]==ht){ X=(x+1024<<11|y+1024)<<6|st2; w=X%P; while(h[w][0]==ht){ if(h[w][1]==X){ maxs(ans,h[w][2]+s); break; } if((w+=1237)>=P)w-=P; } }else{ ds[st]=ht; X=(x+1024<<11|y+1024)<<6|st; w=X%P; while(h[w][0]==ht){ if(h[w][1]==X){ maxs(h[w][2],s); return; } if((w+=1237)>=P)w-=P; } h[w][0]=ht; h[w][1]=X; h[w][2]=s; } } void dfs(int w,int x,int y,int s){ if(w)ins(st,x,y,s); if(w<3) for(int i=0;i<n;++i)if(!ed[i]){ ed[i]=1; st^=1<<i; int v=r[i]; for(int j=0;j<pp[v];++j){ int a=ps[v][j][0],b=ps[v][j][1]; cal(w+1,x,y,a,b,s); cal(w+1,x,y,a,-b,s); cal(w+1,x,y,-a,b,s); cal(w+1,x,y,-a,-b,s); cal(w+1,x,y,b,a,s); cal(w+1,x,y,b,-a,s); cal(w+1,x,y,-b,a,s); cal(w+1,x,y,-b,-a,s); } st^=1<<i; ed[i]=0; } } int main(){ for(int i=1;i<=300;++i){ for(int j=0;j*j*2<=i*i;++j){ int z=sqrt(i*i-j*j)+1e-10; if(j*j+z*z==i*i)ps[i][pp[i]][0]=j,ps[i][pp[i]++][1]=z; } } while(scanf("%d",&n)==1&&n){ for(int i=0;i<n;++i)scanf("%d",r+i); ans=0; ++ht; dfs(0,0,0,0); if(!ans)puts("-1"); else if(~ans&1)printf("%d\n",ans>>1); else printf("%d.5\n",ans>>1); } return 0; }