【BZOJ 2458 最小三角形】
阿新 • • 發佈:2017-10-12
|| 左右 tool online 難度 題解 esp cstring htm Time Limit: 10 Sec Memory Limit: 128 MB
Sample Input
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 最小三角形】