POJ1113浅析——Wall ——凸包

题目大意:

        要在一座城堡周围建围墙,要求用料最省。围墙距城堡不得小于 距离 L。

浅析:

        题目要求用料最省,求围墙长度。因此只要找一个最小的多边形能够围住城堡即可。因此是一个求凸包周长的问题。

        距离不得小于L。因此凸包顶点会形成扇形。各扇形聚在一起形成了一个圆。

       所以所求周长 = 凸包周长 + 一个圆的周长。

    

        因为这个题数据量不大,graham中的极角排序我还不会,所以用了卷包裹的方法来求凸包。

        卷包裹法最后得到的点并不一定是凸包顶点,所以每确定一个点,一定要判断一下是不是终点。(即判断它的后继点是否在凸包起点的左侧,如果是,那这个点就是凸包终点,与起点连载一起形成凸包)。

        卷包裹过程中依次更新周长sum值。然后加上起点终点的长度,再加上圆的周长,就得到了所求值。

 

我的代码如下:(供参考)

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<math.h>
#define Pi 3.1415926535898
#define inf 10001

struct Point
{
    int x, y;
    int mark;       
}a[1010];

int left(int minp, int num, int i)
{
    return (a[num].x-a[minp].x)*(a[i].y-a[minp].y)-(a[i].x-a[minp].x)*(a[num].y-a[minp].y);    
}
double dis(int minp, int num, int i)
{
    return sqrt( (a[i].x-a[minp].x)*(a[i].x-a[minp].x)+(a[i].y-a[minp].y)*(a[i].y-a[minp].y) ) - sqrt( (a[num].x-a[minp].x)*(a[num].x-a[minp].x)+(a[num].y-a[minp].y)*(a[num].y-a[minp].y) );      
}
double dist(int minp, int num)
{
    return sqrt( (a[num].x-a[minp].x)*(a[num].x-a[minp].x)+(a[num].y-a[minp].y)*(a[num].y-a[minp].y) ); 
}
int min(int m, int n)
{
    if(m<n) return m;
    return n;
}
int max(int m, int n)
{
    if(m>n)  return m;
    return n;   
}
int online(int minp, int num, int tmp)
{
    if( a[num].x >= min(a[minp].x, a[tmp].x) && a[num].x<=max(a[minp].x, a[tmp].x) )
        return 1;
    return 0;    
}

int main()
{
    int i, n, l, minx=inf, miny=inf, minp, time, num, tmp;
    double sum=0.0;
    scanf("%d%d", &n, &l);
    for(i=0; i<n; i++)
    {
        scanf("%d%d", &a[i].x, &a[i].y);
        a[i].mark = 1;
        if(a[i].y<miny || (a[i].y==miny && a[i].x<minx) )
        {  
            miny = a[i].y;  
            minx = a[i].x;
            minp = i;
        }   
    }
    tmp = minp;
    a[minp].mark = 0;
    time = 0;
    while(time!=n-1) 
    {   
        //卷包裹法求下一个凸包顶点 
        for(i=0; i<n; i++)
        {
            if(a[i].mark)
            {
                num=i; 
                break;           
            }         
        }
        for(i=0; i<n; i++)
        {
            if(a[i].mark && i!=num && (left(minp, num, i)<0||(left(minp, num, i)==0&&dis(minp, num, i)<0)))
            {
                    num=i;       
            }         
        }
        
        //判断 minp点是不是凸包终点,如果是,则与其连接的点为起点 
        if(minp!=tmp && (left(minp, num, tmp) < 0 || (left(minp,  num, tmp)==0 && online(minp, num, tmp) ) ) )
        {   
            num=tmp;   
            break;  
        }
        sum = sum + dist(minp, num);
        minp = num;
        a[num].mark = 0;   //标记为凸包顶点 
        time++;           //最坏情况下循环次数time = n-1 
        
    } 
    //printf("sum=%lf\n", sum);
    sum += (Pi * l * 2 + dist(minp, tmp)); //凸包周长(+起点和终点的距离)+一个圆周长
    printf("%.0f\n", sum);
    //system("pause");
    return 0;    
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值