測試地址:Wall
題目大意:一個國王有n個城堡(可以看做平面上的點),現在要建一堵封閉的城墻將所有城堡圍住,并且使得城墻與每座城堡的最短距離不超過L,求滿足條件的最短城墻長度。
做法:可以證明,最短城墻長度等于這n個點的凸包周長加上一個半徑為L的圓的周長,所以問題就轉變為求這n個點的凸包,這里用基于極角排序的Graham-Scan算法來求凸包,時間復雜度為O(nlogn)。輸出要注意,如果選C++就是%.0lf,如果選G++就是%.0f,否則會WA,我也不知道為什么......
以下是本人代碼:
#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>#include <cmath>#define pi 3.14159265#define e 0.00000001using namespace std;int n,s[1010],top=1;double l,ans=0;struct point{ double x,y; point Operator - (point b) { point s; s.x=x-b.x; s.y=y-b.y; return s; }}p[1010];double multi(point a,point b){ return a.x*b.y-b.x*a.y;}double dist(point a,point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}bool cmp(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){ double m=multi(a-p[1],b-p[1]); if (fabs(m)<=e) return dist(a,p[1])<dist(b,p[1]); return m>0;}void graham(){ top=2,s[1]=1,s[2]=2; for(int i=3;i<=n;i++) { while(top>1&&multi(p[s[top]]-p[s[top-1]],p[i]-p[s[top]])<=0) top--; s[++top]=i; }}int main(){ scanf("%d%lf",&n,&l); for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); sort(p+1,p+n+1,cmp); sort(p+2,p+n+1,cmp2); graham(); for(int i=1;i<top;i++) ans+=dist(p[s[i]],p[s[i+1]]); ans+=dist(p[1],p[s[top]]); ans+=pi*2*l; PRintf("%.0f",ans); return 0;}
新聞熱點
疑難解答