BZOJ-2829信用卡凸包 凸包+向量旋转计算

来源:互联网 发布:淘宝怎么改掌柜名字 编辑:程序博客网 时间:2024/05/16 15:12

大家都很强, 可与之共勉 。

题意:
  给定一个规模的矩形,长为a,宽为b,其中它的四个角是一个半径为r14圆。给您n个这样的图形,以x,y,θ这样的三元组给出,表示其中心坐标(对角线交点),相对于x正半轴的逆时针旋转角度。

  问您这个图形的凸包周长是多少,保留两位小数。
  其中n100000.1a,b1000000.00.0r<min(a4,b4)|x|,|y|1000000.00θ<2π

题解:

  把所有矩形(未进行圆滑处理)的顶点找出,然后直接找凸包,最后加上一个圆的周长。因为凸包是凸多边形,内角和是2π。所以这个做法具有正确性。

  那么问题就在于如何找顶点(顺便吐槽网上的做法劳资看不懂),用到向量的旋转。

  (没有画图工具……)
  设要旋转的向量为z,建系化为基底表示为(x,y),设旋转后的向量为z。设zx正半轴的夹角为α,旋转角度为β

  可以知道的是,旋转前后模长不变,设为r
  于是原来向量的坐标可以表示为(rcosα,rsinα)
  旋转后的向量可以表示为(rcos(α+β),rsin(α+β))

  由和角公式

z=(r(cosαcosβsinαsinβ),r(sinαcosβ+sinβcosα))

z=(rcosαcosβrsinαsinβ,rsinαcosβ+rsinβcosα))

因为

x=rcosα,y=rsinα

所以
z=(xcosβysinβ,ycosβ+xsinβ))

然后就很简单了……

话说突然发现自己凸包的板子有一步多余了

/**************************************************************    Problem: 2829    User: Lazer2001    Language: C++    Result: Accepted    Time:108 ms    Memory:13804 kb****************************************************************/# include <bits/stdc++.h>const double eps = 1e-8 ;const double Pi = acos ( -1 ) ;inline int dcmp ( double x )  {    return ( x > -eps ) - ( x < eps ) ;}typedef struct Vector  {    double x, y ;    Vector ( )  {   }    Vector ( double x, double y ) : x ( x ), y ( y )  {     }    inline Vector operator - ( const Vector& rhs )  const  {        return Vector ( x - rhs.x, y - rhs.y ) ;    }    inline Vector operator + ( const Vector& rhs )  const  {        return Vector ( x + rhs.x, y + rhs.y ) ;    }    inline double operator % ( const Vector& rhs )  const  {        return x * rhs.y - y * rhs.x ;    }}  Vector, Point ;struct Pcmp  {    inline bool operator ( ) ( const Point& a, const Point& b ) const {        return ( a.x == b.x ) ? a.y < b.y : a.x < b.x ;    }} ;int Graham ( Point* p, int n, Point* res )  {    std :: sort ( p, p + n, Pcmp ( ) ) ;    register int tp ( 1 ) ;    for ( int i = 0 ; i < 2 ; ++ i )  res [i] = p [i] ;    for ( int i = 2 ; i < n ; ++ i )  {        while ( tp && dcmp ( ( p [i] - res [tp - 1] ) % ( res [tp] - res [tp - 1] ) ) >= 0 )  -- tp ;        res [++ tp] = p [i] ;    }    int len = tp ;    res [++ tp] = p [n - 2] ;    for ( int i = n - 3 ; i >= 0 ; -- i )  {        while ( tp != len && dcmp ( ( p [i] - res [tp - 1] ) % ( res [tp] - res [tp - 1] ) ) >= 0 )  -- tp ;        res [++ tp] = p [i] ;    }    return tp ;}# define N 400010Point p [N], con [N] ;# undef Ninline Point Rotate ( Point a, double rad )  {      return Point ( a.x * cos ( rad ) - a.y * sin ( rad ), a.y * cos ( rad ) + a.x * sin ( rad ) ) ;  }int main ( )  {    int n ;    scanf ( "%d", & n ) ;    double a, b, r ;    scanf ( "%lf%lf%lf", & a, & b, & r ) ;    a -= 2 * r, b -= 2 * r ;    int cnt ( 0 ) ;    while ( n -- )  {        static double x, y, angle ;        scanf ( "%lf%lf%lf", & x, & y, & angle ) ;        Vector cur = Vector ( x, y ) ;        p [cnt ++] = cur + Rotate ( Vector ( b / 2, a / 2 ), angle ) ;        p [cnt ++] = cur + Rotate ( Vector ( - b / 2, a / 2 ), angle ) ;        p [cnt ++] = cur + Rotate ( Vector ( b / 2, - a / 2 ), angle ) ;        p [cnt ++] = cur + Rotate ( Vector ( - b / 2, - a / 2 ), angle ) ;    }    int ccnt = Graham ( p, cnt, con ) ;    con [ccnt] = con [0] ;    double ans ( 0 ) ;    for ( int i = 0 ; i < ccnt ; ++ i )  {        ans += hypot ( con [i].x - con [i + 1].x, con [i].y - con [i + 1].y ) ;    }    printf ( "%.2lf\n", ans + 2 * r * Pi ) ;    return 0 ;}