pku1113 grahamScan求凸包周长

ContractedBlock.gif ExpandedBlockStart.gif Code
//借鉴了一下牛人的程序,终于AC,63MS
//题意:求坐标上的点构成的凸包,不过题目有个难点,就是要将wall距离城堡r远,有公式wall=2*pi*r+len(凸包)
#include <iostream>
#include 
<cmath>
#include 
<vector>
#include 
<algorithm>
using namespace std;

const int MAXN = 1010;
const double pi = acos(-1.0);
typedef 
struct
{
    
double x,y;
    
double thera;
}Point;
vector
<Point>p;
int S[MAXN];

bool cmp1(Point &a,Point &b)
{
    
if( a.y == b.y ) return a.x < b.x;
    
return a.y < b.y;
}

bool cmp2(Point &a,Point &b)
{
    
if( a.thera == b.thera ) //极角相同按极半径降序
        return sqrt(a.x*a.x+a.y*a.y) > sqrt(b.x*b.x+b.y*b.y);
    
else return a.thera < b.thera;
}

bool cmp3(const Point &a,const Point &b)
{
    
return (a.thera == b.thera);
}

bool xmult(Point p0, Point p1, Point p2)
{
    
int xa = p1.x-p0.x, ya = p1.y-p0.y,
        xb 
= p2.x-p1.x, yb = p2.y-p1.y;
    
if (!(xa*yb - xb*ya < 0))
        
return true;
    
else     
        
return false;
}

double dis(Point p1,Point p2)
{
    
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

double graham_scan()
{
    
int i,num = p.size();
    Point 
*t;
    
    sort(p.begin(),p.end(),cmp1);

    Point p0 
= p[0];
    
for( i = 0 ; i < p.size() ; i ++ )
    {
        p[i].x 
-= p0.x; p[i].y -= p0.y;
        p[i].thera 
= atan2(1.0*p[i].y,1.0*p[i].x);//算出i点与原点构成直线和x轴夹角
    }

    sort(p.begin()
+1,p.end(),cmp2);
    vector
<Point>::iterator itr = unique(p.begin()+1,p.end(),cmp3);
    
if( itr != p.end() )
    {
        p.erase(itr,p.end());
        num 
= p.size();
    }
    
    
int top = -1;
    S[
++top] = 0;
    S[
++top] = 1;
    S[
++top] = 2;
    
for( i = 3 ; i < num ; i ++ )//grahamScan扫描法
    {
        
while( xmult(p[S[top-1]],p[S[top]],p[i]) == false )
             
--top;
        S[
++top] = i;
    }
    
    
for( i = 0 ; i <= top ; i ++ )
    {
        p[S[i]].x 
+= p0.x;
        p[S[i]].y 
+= p0.y;
        
//printf("%.lf,%.lf\n",p[S[i]].x,p[S[i]].y);
    }
    
double ans = dis(p[S[0]],p[S[top]]);//计算凸包长度
    for( i = 1 ; i <= top ; i ++ )
    {
        ans 
+= dis(p[S[i]],p[S[i-1]]);
    }
    
return ans;
}

int main()
{
    
int N,i;
    
double x,y,r;
    Point t;
    
//freopen("1113.txt","r",stdin);
    while( scanf("%d %lf",&N,&r) != EOF )
    {
        
for( i = 0 ; i < N ; i ++ )
        {
            scanf(
"%lf %lf",&t.x,&t.y);
            p.push_back(t);
        }

        
double ans = graham_scan();

        ans 
+= 2.0*pi*r;
        printf(
"%.lf\n",ans);
    }
    
return 0;
}

转载于:https://www.cnblogs.com/shenyaoxing/archive/2009/10/10/1580614.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值