P4423 [BJWC2011] 最小三角形 与 SP7209 CLOSEST - Closest Triplet
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;
}