Poj 1113 凸包问题


题目大意:输入N个点坐标,求凸包周长加上一个以M为半径的圆的周长。


解题思路:首先解决凸包,

解决凸包的首要问题,是算法,这里用Graham_scan扫描算法。

第一步:存入点,开辟一个数组;

第二步:在输入点之后的同时,进行在保证y坐标最小的情况下,x坐标最小的点的寻找。用个if判断。记下该点的位置i;

第三步:已经跳出输入的循环,进行一次交换,最小y,x点与存点数组的第一个元素下标为0的互换点值。

第四步:排序:这里使用快排函数:首先第一步:建立比较函数:比较函数的建立需要判断函数,即叉乘的判断。叉乘的判断也就是极角大小的判断

                                                                       第二步:进行排序;

第五步:建立一个点栈,用以存凸包上的点。

第六步:根据极角的值依次将排好序的数组下标为0,1,2的元素入栈。

第七步:从存点数组下标为3的点开始判断,这里的判断是根据栈的顶端两个元素和存点数组的第i个元素进行的判断。i是for循环的。这个判断的意义在于判断这三个点所形成的角是不是大于180度,小于180度继续扫描下一个点,若大于180度说明第二个点一定在凸包内部,然后我们暂时停止扫描下一个点,将指向栈顶的元素top减一,继续执行这个判断。直到三点所形成的角小于180度。

第八步:第七步结束之后凸包上的点就都存在了栈里面了。然后我们就开始计算凸包的周长,用一个函数即可。

第九步:输出凸包周长和以M为半径的圆的周长的相加总和就是题目所求的答案了。


首先解释下这个提交后的运行时间Time为0MS的蕴意,我连续提交过20次,第一次是0MS,第二次是16MS,第三次32,第四次16,第五次32,第六次16,第七次0,然后就是这么一直的下去,差不多就都是这三种情况0,16,32。代码是相同的。内存的话,你把结构体里的int 改成short可以减少8K的 开销。

Source Code

Problem: 1113  User: 201141919106 
Memory: 208K  Time: 0MS 
Language: C++  Result: Accepted 

Source Code 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX 1001
#define Pi 3.14159265
typedef struct
{
    int x,y;
}Point;
Point PointSet[MAX];//第一步
Point ch[MAX];//第五步
int multiply(Point p1,Point p2,Point p0)//判断极角大小
{
    return (p1.y-p0.y)*(p2.x-p0.x)-(p2.y-p0.y)*(p1.x-p0.x);
}
int multi(Point p1,Point p2,Point p3)//判断三点组成的角度
{
    return (p3.y-p2.y)*(p2.x-p1.x)-(p2.y-p1.y)*(p3.x-p2.x);
}

int dis(Point p1,Point p2)
{
    return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
}
int cmp(const void* pp,const void* qq)//排序判断条件
{
    Point p1,p2;
    p1=*(Point*) pp; p2=*(Point*) qq;
    if(multiply(p1,p2,PointSet[0])>0)
        return 1;
    else if(multiply(p1,p2,PointSet[0])==0 && dis(p1,PointSet[0])>dis(p2,PointSet[0]))//极角相等的情况下,要距离最远的那个。
        return 1;
    return -1;
}
double Graham_scan(int n,int m)
{
    int i,j,k=0;
    int top=2;
    double len=0;
    ch[0]=PointSet[0];//第六步
    ch[1]=PointSet[1];
    ch[2]=PointSet[2];
    for (i=3; i<n; i++)//第七步
    {
        while(multi(ch[top-1],ch[top],PointSet[i])<0) top--;
        ch[++top]=PointSet[i];
    }
    for(i=1; i<=top; i++)//第八步,因为进过这个循环后,下标为0和top的点之间的距离为算进去,所以有了下面那个加法
    {
        len+=sqrt((double)dis(ch[i],ch[i-1]));
    }
    len+=2*m*Pi+sqrt((double)dis(ch[0],ch[top]));//第九步
    return len;
}
int main()
{
    int n,m,i,min;
    Point minPoint;
    scanf("%d%d",&n,&m);
    for(i=0; i<n; i++)
    {
        scanf("%d%d",&PointSet[i].x,&PointSet[i].y);//第二步
        if(minPoint.x>PointSet[i].x)
            {
                minPoint=PointSet[i];
                min=i;
            }
            else if(minPoint.x==PointSet[i].x && minPoint.y>PointSet[i].y)
            {
                minPoint=PointSet[i];
                min=i;
            }
    }
    PointSet[min]=PointSet[0];PointSet[0]=minPoint;//第三步
    qsort(PointSet+1,n-1,sizeof(PointSet[0]),cmp);//第四步---
    printf("%.lf\n",Graham_scan(n,m));//输出
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值