hdu1392-Surround the Trees 求凸包

问题描述
有很多树在一个区域。 一个农民想买一根绳子环绕这些树木。 首先他必须知道所需的最小长度的绳子。 然而,他不知道如何计算它。 你能帮助他吗?
树木的直径和长度都省略了,这意味着树可以被视为一个点。 绳子的厚度也省略了这意味着一根绳子可以被看作是一条直线.没有超过100棵树。
输入
输入包含一个或多个数据集。 每个输入的第一行数据集数量的树木在这个数据集,它是紧随其后的是一系列的坐标的树。 每一对坐标是一个正整数,每个整数小于32767。 每一对由空格分隔。

零数量的树木终止程序的输入。
 
输出
最小长度的绳子。 精度应该10 ^ -2。
Sample Input
    
    
9 12 7 24 9 30 5 41 9 80 7 50 87 22 9 45 1 50 7 0
 
Sample Output
    
    
243.06
这是一道关于凸包的计算几何题,也是一道Graham算法的经典模板题。

所谓凸包,在《算法导论 》第599页有这样的解释:多边形是平面上由一系列线段构成的闭合曲线。也就是说,它由一系列直线段构成的首尾相连的曲线。这些直线段称为多边形的边。一个连接两条连续边的顶点称为多边形的顶点。如果多边形是简单的,那么它的内部不存在边交叉的情况。在平面上被简单多边形包围的点集组成了该多边形的内部,恰落在多边形上的点组成了多边形的边界,而包围该多边形的点构成 了多边形的外部。对于一个简单多边形,如果给定任意两个位于其边界或内部的点,连接这两个点的线段上的所有点都在这个多边形的边界或内部,那么该多边形为凸多边形

了解完凸包,我们就需要知道如何求得凸包,所以在这里我用到的是Graham算法。
在《算法导论》中对Graham算法有如下描述:
Graham扫描算法
     Graham扫描法通过维持一个关于候选点的栈S来解决凸包问题。输入集合Q中的每个点都被压入栈一次,非CH(Q)中顶点的点最终被弹出栈,当算法终止时,栈S中仅包含CH(Q)中的顶点,以逆时针的顺序出现在边界上。
     过程的输入为点集Q,其中|Q|>=3.在无需改变栈S的情况下,调用函数TOP(S)和函数分别返回处于栈顶的点和处于栈顶部下面的那个点。
返回的是栈S从底部到顶部,依次是按逆时针方向排列的CH(Q)中的顶点。
下面是Graham 算法伪代码
Graham-scan(Q)
  let p0 be the point in Q with the minimum y-coordinate,
         or the leftmost such point in case of a tie
  let (p1,p2,...pm) be the remaining points in Q,
    sorted by polar angle in counterclockwise order around p0
      (if more than one point has the same angle ,remove all but
         the one that is farthest from p0)
   if(m<2)
      return "convex hull is empty"
   else let S be an empty stack
     PUSH(p0,S)
     PUSH(p1,S)
     PUSH(p2,S)
   for i=3 to m
      while the angle formed by points NEXT-TO-TOP(S),TOP(S),
             and pi makes a nonleft turn
      POP(S)
    PUSH(pi,S)
return S
下面给出图示:









AC代码:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct 
{
        double x , y ;
}POINT ;
POINT result[110] ;// 模拟堆栈S,保存凸包上的点
POINT tree[110] ;
int n , top ;
double Distance ( POINT p1 , POINT p2 ) 
{
       return sqrt( (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y) ) ;
}
double Multiply(POINT p1 , POINT p2 , POINT p3) // 叉积 
{
       return ( (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x) ) ;
}
int cmp ( const void *p1 , const void *p2 )
{
    POINT *p3,*p4;
    double m;
    p3 = (POINT *)p1; 
    p4 = (POINT *)p2; 
    m = Multiply(tree[0] , *p3 , *p4) ;
    if(m < 0) return 1;
    else if(m == 0 && (Distance(tree[0] , *p3) < Distance(tree[0],*p4)))
        return 1;
    else return -1;
}
void Tubao ()
{
     int i ; 
     result[0].x = tree[0].x;
     result[0].y = tree[0].y;
     result[1].x = tree[1].x;
     result[1].y = tree[1].y;
     result[2].x = tree[2].x;
     result[2].y = tree[2].y;
     top = 2;
     for ( i = 3 ; i <= n ; ++ i )
     {
         while (Multiply(result[top - 1] , result[top] , tree[i]) <= 0 )
               top -- ;                          //出栈
          result[top + 1].x = tree[i].x ;
          result[top + 1].y = tree[i].y ;
          top ++ ;
     }


}
int main ()
{
    int pos ;
    double len , temp , px , py ;
    while ( scanf ( "%d" , &n ) != EOF , n )
    {
          py = -1 ;
          for ( int i = 0 ; i < n ; ++ i )
          {
              scanf ( "%lf%lf" , &tree[i].x , &tree[i].y ) ;
              
          }
          if ( n == 1 )
          {
               printf ( "0.00\n" ) ;
               continue ;
          }
          else if ( n == 2 )
          {
               printf ( "%.2lf\n" , Distance(tree[0] , tree[1]) ) ;
               continue ;
          }
          for ( int i = 0 ; i < n ; ++ i )
          {
              if(py == -1 || tree[i].y < py)
                  {
                       px = tree[i].x;
                       py = tree[i].y;
                       pos = i;
                  }
                  else if(tree[i].y == py && tree[i].x < px)
                  {
                       px = tree[i].x;
                       py = tree[i].y;
                       pos = i;
                  }
          }
          temp = tree[0].x ;                      // 找出y最小的点 
          tree[0].x = tree[pos].x ;
          tree[pos].x = temp ;
          temp = tree[0].y ;
          tree[0].y = tree[pos].y ;
          tree[pos].y = temp ;
          qsort(&tree[1],n - 1,sizeof(double) * 2,cmp);
          tree[n].x = tree[0].x;
          tree[n].y = tree[0].y;
          Tubao();
          len = 0.0;
          for(int i = 0 ; i < top ; i ++)
               len = len + Distance(result[i] , result[i+1]) ;
          printf("%.2lf\n",len);
   
    }
    return 0 ;
}

题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1392



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值