noi 模擬賽 t1,所以打了些部分分,不介意吧……
思路:
仿照平面最近點對思路,先按照橫座標排序,考慮分治。
對於分割線 \(y=X\),考慮求跨過這條線的貢獻,設 \(d\) 為左邊和右邊分治結果的最小值,則這三點中最長邊的長度必須 \(\le \frac{d}{2}\),不然不會比 \(d\) 更優。
則我們只需要考慮橫座標到分割線的距離 \(\le \frac{d}{2}\) 的貢獻,將這些點找出來,再按照縱座標進排序,這裡使用歸併排序的話可以降一個 \(\log\),但是沒必要。
然後暴力列舉這 \(3\) 個點,使得三個點的 \(y\) 座標的極差 \(\le \frac{d}{2}\),然後計算貢獻即可。
時間複雜度為 \(O(N \log^2 N)\)。
P4423 [BJWC2011] 最小三角形 Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=1e6+10,INF=1e18;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct Point{
db x,y;
friend bool operator==(const Point &a,const Point &b){
return a.x==b.x&&a.y==b.y;
}
friend db dis(const Point &a,const Point &b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
}a[N];
ll n,sum;
namespace Sub1{
db ans=INF;
void work(){
For(i,1,n)
For(j,i+1,n)
For(k,j+1,n)
ans=min(ans,dis(a[i],a[j])+dis(a[j],a[k])+dis(a[i],a[k]));
printf("%.10lf\n",ans);
}
};
namespace Sub2{
db ans=INF;
bool cmp(Point &a,Point &b){
return a.x<b.x;
}
void work(){
sort(a+1,a+n+1,cmp);
For(i,1,n-2)
ans=min(ans,dis(a[i],a[i+1])+dis(a[i+1],a[i+2])+dis(a[i],a[i+2]));
printf("%.10lf\n",ans);
}
};
namespace Sub3{
ll cnt=0;
Point b[N];
db ans=INF;
bool cmp1(Point &a,Point &b){
if(a.x!=b.x)
return a.x<b.x;
return a.y<b.y;
}
bool cmp2(Point &a,Point &b){
if(a.y!=b.y)
return a.y<b.y;
return a.x<b.x;
}
db solve(ll l,ll r){
if(l==r)
return INF;
ll mid=(l+r)>>1;
ll I=a[mid].x;
db d=min(solve(l,mid),solve(mid+1,r));
cnt=0;
For(i,l,r)
if(abs(a[i].x-I)<=d/2)
b[++cnt]=a[i];
sort(b+1,b+cnt+1,cmp2);
For(i,1,cnt){
For(j,i+1,cnt){
if(b[j].y-b[i].y>d/2)
break;
For(k,j+1,cnt){
if(b[k].y-b[i].y>d/2)
break;
d=min(d,dis(b[i],b[j])+dis(b[i],b[k])+dis(b[j],b[k]));
}
}
}
return d;
}
void work(){
sort(a+1,a+n+1,cmp1);
printf("%.10lf\n",solve(1,n));
}
};
int main(){
open("A.in","A.out");
n=read();
For(i,1,n){
a[i]={(db)read(),(db)read()};
sum+=a[i].y;
}
if(n<=100)
Sub1::work();
else if(!sum)
Sub2::work();
else
Sub3::work();
return 0;
}
SP7209 CLOSEST - Closest Triplet Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=2e5+10,INF=1e18;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct Point{
db x,y;
friend bool operator==(const Point &a,const Point &b){
return a.x==b.x&&a.y==b.y;
}
friend db dis(const Point &a,const Point &b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
}a[N];
ll n,sum;
namespace Sub1{
db ans=INF;
void work(){
For(i,1,n)
For(j,i+1,n)
For(k,j+1,n)
ans=min(ans,dis(a[i],a[j])+dis(a[j],a[k])+dis(a[i],a[k]));
printf("%.3lf\n",ans);
}
};
namespace Sub2{
db ans=INF;
bool cmp(Point &a,Point &b){
return a.x<b.x;
}
void work(){
sort(a+1,a+n+1,cmp);
For(i,1,n-2)
ans=min(ans,dis(a[i],a[i+1])+dis(a[i+1],a[i+2])+dis(a[i],a[i+2]));
printf("%.3lf\n",ans);
}
};
namespace Sub3{
ll cnt=0;
Point b[N];
db ans=INF;
bool cmp1(Point &a,Point &b){
if(a.x!=b.x)
return a.x<b.x;
return a.y<b.y;
}
bool cmp2(Point &a,Point &b){
if(a.y!=b.y)
return a.y<b.y;
return a.x<b.x;
}
db solve(ll l,ll r){
if(l==r)
return INF;
ll mid=(l+r)>>1;
ll I=a[mid].x;
db d=min(solve(l,mid),solve(mid+1,r));
cnt=0;
For(i,l,r)
if(abs(a[i].x-I)<=d/2)
b[++cnt]=a[i];
sort(b+1,b+cnt+1,cmp2);
For(i,1,cnt){
For(j,i+1,cnt){
if(b[j].y-b[i].y>d/2)
break;
For(k,j+1,cnt){
if(b[k].y-b[i].y>d/2)
break;
d=min(d,dis(b[i],b[j])+dis(b[i],b[k])+dis(b[j],b[k]));
}
}
}
return d;
}
void work(){
sort(a+1,a+n+1,cmp1);
printf("%.3lf\n",solve(1,n));
}
};
int main(){
while(1){
n=read();
if(n==-1)
break;
For(i,1,n){
a[i]={(db)read(),(db)read()};
sum+=a[i].y;
}
if(n<=100)
Sub1::work();
else if(!sum)
Sub2::work();
else
Sub3::work();
}
return 0;
}