1. 程式人生 > >【BZOJ 2458 最小三角形】

【BZOJ 2458 最小三角形】

|| 左右 tool online 難度 題解 esp cstring htm

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1551 Solved: 549
[Submit][Status][Discuss]

Description

Xaviera現在遇到了一個有趣的問題。
平面上有N個點,Xaviera想找出周長最小的三角形。
由於點非常多,分布也非常亂,所以Xaviera想請你來解決這個問題。
為了減小問題的難度,這裏的三角形也包括共線的三點。

Input

第一行包含一個整數N表示點的個數。
接下來N行每行有兩個整數,表示這個點的坐標。

Output

輸出只有一行,包含一個6位小數,為周長最短的三角形的周長(四舍五入)。

Sample Input

4
1 1
2 3
3 3
3 4

Sample Output

3.414214

HINT

100%的數據中N≤200000。

Source

Day1

題解:

①cdq分治:對點的x坐標排序,然後進行分治,同時分治完了還需要求兩邊的互相影響。

一、在左邊取兩個點,右邊一個。二、在右邊取兩個點,左邊一個。

②再對分治左右兩邊的點再分別按照y值排序,

③剪枝:因為已經出來了一個比較優的ans,所以當一個點距離兩邊中界過遠,那麽我們就把它扔掉再不用管了。還有就是兩邊的點,y坐標距離過大的也不能進行選擇,所以又進行一次剪枝。

④把上述東西串起來的是暴力枚舉。

#include<cmath>
#include<cstdio>
#define eps 1e-9
#include<cstring>
#include<algorithm>
#define go(i,a,b) for(int i=a;i<=b;i++)
#define ro(i,a,b) for(int i=a;i>=b;i--)
using namespace std;const int N=200010;
struct P{double x,y;bool operator<(const P &a)const{return y<a.y;}}s[N],newq[N],tmp[N];
double ans=1e9;int n;double sqr(double x){return x*x;}bool cmp(P a,P b){return a.x<b.x;}
double dis(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
double Cal(P a,P b,P c){return dis(a,b)+dis(b,c)+dis(c,a);}
void solve(int l,int r)
{
    int mid=(l+r)>>1,top=0,tp1=l,tp2=mid+1,Mid=s[mid].x;
    if(r-l+1<=3){sort(s+l,s+r+1);if(r-l+1==3)ans=min(ans,Cal(s[l],s[l+1],s[r]));return;}
    
    solve(l,mid);solve(mid+1,r);
   	go(i,l,r)if((s[tp1]<s[tp2]||tp2>r)&&tp1<=mid)tmp[i]=s[tp1++];else tmp[i]=s[tp2++];
    memcpy(s+l,tmp+l,sizeof(P)*(r-l+1));
    
    go(i,l,r)if(abs(s[i].x-Mid)<ans/2)newq[++top]=s[i];
    go(i,1,top)ro(j,i-1,1)
    {
        if(newq[i].y-newq[j].y>=ans/2)break;
        ro(k,j-1,1)ans=min(ans,Cal(newq[i],newq[j],newq[k]));   
    }
}
int main()
{	
    scanf("%d",&n);go(i,1,n) 
	scanf("%lf%lf",&s[i].x,&s[i].y);
	sort(s+1,s+n+1,cmp);
    solve(1,n);printf("%.6f\n",ans);
}//Paul_Guderian

燃燒的河流推倒了祈禱者的燈塔,

告誡的引擎怒吼著聖潔的墓誌銘。——————汪峰《貧瘠之歌》

【BZOJ 2458 最小三角形】