Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 26286 | Accepted: 8760 |
Description
Input
Output
Sample Input
9 100 200 400 300 400 300 300 400 300 400 400 500 400 500 200 350 200 200 200
Sample Output
1628
Hint
题目大意:
有一个贪心的国王,他要你的朋友帮他围着他的城堡砌墙,然而他要求你的墙总是隔他的城堡L的距离,并且要求你使用的墙面长度(周长)最小,不然就砍了你朋友。输入给出N个点的坐标构成这个城堡,给出距离L。
解题思路:
大家可以动手画一画给出的样例(很快就画完了)。发现当点 i 和 i+1 和 i+2 是一条直线的时候,也就是两条线段中间不转弯的情况下,我们的周长直接加线段长就好了。但是如果中间出现了转交,那么有两种情况。让我们看看下面的图:
从图中可以看出,如果出现了这样的两个角,那么还不如我们直接砌直线。所以我们可以得出我们构造的最短周长,应该是构造一个凸包。我们的周长就是所有的直线长度加上转角的特殊弧长。弧长怎么算呢?细心一点就知道每个转角对应的圆心角应该是π-内角(我们作城堡直线路径的垂线看看!)。
由此我们再加上这些弧长就是我们的答案了!
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; #define eps 10e-9 #define MAX 1002 struct Point { double x,y; Point() {} Point ( double x , double y ) : x(x) , y(y) {} }; typedef Point Vector; Point operator - ( Point a , Point b ) { return Point ( a.x - b.x , a.y - b.y ); } bool cmp ( Point a, Point b ) { if ( a.x != b.x ) return a.x < b.x; else return a.y < b.y; } double Length ( Vector v ) { return sqrt ( v.x * v.x + v.y * v.y ); } double Dot ( Vector u , Vector v ) { return u.x * v.x + u.y * v.y; } int dcmp ( double x ) { if ( fabs ( x ) < eps ) return 0; else return x < 0 ? -1 : 1 ; } double Distance ( Point a , Point b ) { return sqrt ( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) ); } double Cross ( Vector u , Vector v ) { return u.x * v.y - u.y * v.x; } double Angle ( Vector u , Vector v ) { return acos ( Dot ( u , v ) / Length ( u ) / Length ( v ) ); } int ConvexHull ( Point *p , int n , Point *ch ) //求凸包 { int m = 0; sort ( p , p + n , cmp ); for ( int i = 0 ; i < n ; i ++ ) { while ( m > 1 && Cross ( ch[m-1] - ch[m-2] , p[i] - ch[m-2] ) <= 0 ) m --; ch[m++] = p[i]; } int k = m; for ( int i = n - 2 ; i >= 0 ; i -- ) { while ( m > k && Cross ( ch[m-1] - ch[m-2] , p[i] - ch[m-2] ) <= 0 ) m-- ; ch[m++] = p[i]; } if ( n > 1 ) m --; return m; } int main() { int n,l; Point cas[MAX],ch[MAX]; scanf ( "%d %d" , &n , &l ); for ( int i = 0 ; i < n ; i ++ ) scanf ( "%lf %lf" , &cas[i].x , &cas[i].y ); int cnt = ConvexHull ( cas , n , ch ); double ans = 0; for ( int i = 0 ; i < cnt ; i ++ ) ans += Distance ( ch[(i+1)%cnt] , ch[i] ); for ( int i = 0 ; i < cnt ; i ++ ) { double ang = Angle ( ch[(i+2)%cnt] - ch[(i+1)%cnt] , ch[(i+1)%cnt] - ch[i] ); if ( dcmp ( ang ) != 0 ) { ans += ang * l; } } if ( ans - (int)ans - 0.5 > 0 ) printf ( "%d\n" , (int) ans + 1 ); else printf ( "%d\n" , (int)ans ); return 0; }
技巧总结:
凸包在计算几何中占有很重要的地位!