题解:P13449 [GCJ 2009 Finals] Min Perimeter
我们充分发扬人类智慧,随机平移之后按照 \(x^2+y^2\) 排序,取前 \(370\) 个点即可。
但是这样有 \(136900\) 倍常数。
加入剪枝,设当前答案为 \(ans\),如果 \(dis(a_i,a_j)>ans/2\),直接不考虑了,正确性显然,因为三角形周长大于任意一边的两倍。
另外,如果要卡常,直接循环展开。
甚至没有快读。
#include <bits/stdc++.h>
#define fx(i) fixed<<setprecision(i)
using namespace std;
#define int long long
#define endl '\n'
const int maxn=1e6+10,T=370,T2=500;
int n;
struct point{
int x,y;
point(){}
point(int a,int b){x=a,y=b;}
friend bool operator<(point a1,point a2){
return a1.x*a1.x+a1.y*a1.y<a2.x*a2.x+a2.y*a2.y;
}
}a[maxn];
int range(int x){
return rand()*rand()%x;
}
point rpoint(int rngx,int rngy){
return (point){range(rngx),range(rngy)};
}
inline double dis(point a1,point a2){
return (a1.x-a2.x)*(a1.x-a2.x)+(a1.y-a2.y)*(a1.y-a2.y);
}
#define DIS(c) sqrt(dis(a[i],a[c]))+sqrt(dis(a[j],a[c]))
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
srand(time(0));
int TEST;
cin>>TEST;
for(register int tc=1;tc<=TEST;tc++){
cin>>n;
int maxx=LLONG_MIN,maxy=LLONG_MIN;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
// a[i].x+=rst.x,a[i].y+=rst.y;
maxx=max(maxx,a[i].x);
maxy=max(maxy,a[i].y);
}
point rst=rpoint(maxx,maxy);
for(int i=1;i<=n;i++){
a[i].x+=rst.x,a[i].y+=rst.y;
}
// random_shuffle(a+1,a+n+1);
stable_sort(a+1,a+n+1);
double ans=1e11;
for(register int i=1;i<n;++i){
for(register int j=i+1,k=1;j<=n&&k<=T;++k,++j){
if(dis(a[i],a[j])>ans*ans/4)continue;
int c=j+1;
for(;c<=n&&(n-c+1)%7!=0&&c-j+1<=T;++c){
ans=min(ans,sqrt(dis(a[i],a[j]))+sqrt(dis(a[i],a[c]))+sqrt(dis(a[j],a[c])));
}
for(;c+6<=n&&c-j+1<=T;c+=7){
double d0=sqrt(dis(a[i],a[j]));
ans=min({ans,DIS(c)+d0,DIS(c+1)+d0,DIS(c+2)+d0,DIS(c+3)+d0,DIS(c+4)+d0,DIS(c+5)+d0,DIS(c+6)+d0,DIS(c+7)+d0});
}
}
}
cout<<"Case #"<<tc<<": "<<fx(6)<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号