POJ1113浅析——Wall ——凸包

来源:互联网 发布:3d max螺丝数据 编辑:程序博客网 时间:2024/04/30 06:24

题目大意:

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

浅析:

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

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

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

    

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

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

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

 

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

#include<stdio.h>#include<math.h>#include<stdlib.h>#include<math.h>#define Pi 3.1415926535898#define inf 10001struct 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;    }


 

原创粉丝点击