Board Wrapping(計算幾何求凸包加向量的旋轉)

來源:互聯網
上載者:User

標籤:計算幾何



UVA - 10652

Board Wrapping
Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

[Submit]   [Go Back]   [Status]  

Description

Problem B

Board Wrapping

Input: standard input
Output: standard output

Time Limit: 2 seconds


The small sawmill in Mission, British Columbia, has developed a brand new way of packaging boards for drying. By fixating the boards in special moulds, the board can dry efficiently in a drying room.

Space is an issue though. The boards cannot be too close, because then the drying will be too slow. On the other hand, one wants to use the drying room efficiently.

Looking at it from a 2-D perspective, your task is to calculate the fraction between the space occupied by the boards to the total space occupied by the mould. Now, the mould is surrounded by an aluminium frame of negligible thickness, following the hull of the boards‘ corners tightly. The space occupied by the mould would thus be the interior of the frame.

 

 

  Input

On the first line of input there is one integer, N <= 50, giving the number of test cases (moulds) in the input. After this line,N test cases follow. Each test case starts with a line containing one integern, 1< n <= 600, which is the number of boards in the mould. Thenn lines follow, each with five floating point numbers x, y, w, h, j where0 <= x, y, w, h <=10000 and –90° < j <=90°. Thex and y are the coordinates of the center of the board andw and h are the width and height of the board, respectively.j is the angle between the height axis of the board to the y-axis in degrees, positive clockwise. That is, if j = 0, the projection of the board on thex-axis would be w. Of course, the boards cannot intersect.

 

Output

For every test case, output one line containing the fraction of the space occupied by the boards to the total space in percent. Your output should have one decimal digit and be followed by a space and a percent sign (%).

 

Sample Input                              Output for Sample Input

1

4

4 7.5 6 3 0

8 11.5 6 3 0

9.5 6 6 3 90

4.5 3 4.4721 2.2361 26.565

64.3 %

 

Swedish National Contest

 

The Sample Input and Sample Output corresponds to the givenpicture


題意: 有n塊矩形木板,你的任務是用一個面積盡量小的凸多邊形把他們包圍起來,並計算出木板占整個封裝面積的百分比;

         

意解: 所用到的幾何知識有基於水平序的andrew演算法,向量的旋轉和求多邊形的面積等幾何知識;


以下的向量旋轉知識是拷貝別人的;   而對於多邊形的面積求法則很自然;

在二維座標系中,一個位置向量的旋轉公式可以由三角函數的幾何意義推出。

向左轉|向右轉

比如所示是位置向量R逆時針旋轉角度B前後的情況。

      在左圖中,我們有關係:

  x0 = |R| * cosA       =>          cosA = x0 / |R|

  y0 = |R| * sinA        =>          sinA = y0 / |R|

   在右圖中,我們有關係:

  x1 = |R| * cos(A+B)

  y1 = |R| * sin(A+B)

  其中(x1, y1)就是(x0, y0)旋轉角B後得到的點,也就是位置向量R最後指向的點。我們展開cos(A+B)和sin(A+B),得到:

  x1 = |R| * (cosAcosB - sinAsinB)

  y1 = |R| * (sinAcosB + cosAsinB)

  現在把  cosA = x0 / |R| 和 sinA = y0 / |R|  代入上面的式子,得到:

  x1 = |R| * (x0 * cosB / |R| - y0 * sinB / |R|) =>  x1 = x0 * cosB - y0 * sinB

  y1 = |R| * (y0 * cosB / |R| + x0 * sinB / |R|) =>  y1 = x0 * sinB + y0 * cosB

  這樣我們就得到了二維座標下向量圍繞圓點的逆時針旋轉公式。順時針旋轉就把角度變為負:

  x1 = x0 * cos(-B) - y0 * sin(-B) =>  x1 = x0 * cosB + y0 * sinB

  y1 = x0 * sin(-B) + y0 * cos(-B)=>  y1 = -x0 * sinB + y0 * cosB

  現在我要把這個旋轉公式寫成矩陣的形式,有一個概念我簡單提一下,平面或空間裡的每個線性變換(這裡就是旋轉變換)都對應一個矩陣,叫做變換矩陣。對一個點實施線性變換就是通過乘上該線性變換的矩陣完成的。好了,打住,不然就跑題了。

所以二維旋轉變換矩陣就是:

                                           [cosA  sinA]          [cosA -sinA]
                                           [-sinA cosA] 或者  [sinA cosA]

  我們對向量進行旋轉變換可以通過矩陣完成,比如我要向量(x, y)繞原點逆時針旋轉角度A:

                      [x, y] x  [cosA  sinA]     = [x*cosA-y*sinA  x*sinA+y*cosA]       

                                  [-sinA cosA]

      旋轉後的向量為:[x*cosA-y*sinA  x*sinA+y*cosA]


AC代碼:


#include <algorithm>#include <iostream>#include <cstdio>#include <cmath>#define pi acos(-1.0)#define exp 1e-10using namespace std;struct  Point{    double x,y;    Point(double x0 = 0, double y0 = 0) //建構函式,初始化;    {        x = x0;        y = y0;    }    bool operator < (const Point &ant) const //求凸包時需要對x和y排序,注意點不能有重複,有的話要去重;    {        if(ant.x != x) return ant.x > x;        return ant.y > y;    }};typedef Point Vector;Vector operator + (Vector A, Vector B) //自訂重載+運算;{    return Vector(A.x + B.x, B.y + A.y);}Vector operator - (Vector A, Vector B) //自訂重載-運算;{    return Vector(A.x - B.x, A.y - B.y);}Vector Rotate(Vector A, double rad){    return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));}double change(double j) //轉化為弧度制{    return j / 180.0 * pi;}double cross(Vector A, Vector B) //向量的叉積{    return A.x * B.y - A.y * B.x;}class Convex{public:    int convex(Vector *p, int n, Vector *ch) //求凸包    {        sort(p,p + n);        int m = 0;        for(int i = 0; i < n; i++)        {            while(m > 1 && cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= exp) m--;            ch[m++] = p[i];        }        int k = m;        for(int i = n - 2; i >= 0; i--)        {            while(m > k && cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= exp) m--;            ch[m++] = p[i];        }        if(n > 1) m--;        return m;    }    double PolygonArea(Point *p, int n)//求多邊形的面積    {        double area2 = 0.0;        for(int i = 1; i < n - 1; i++)        {            area2 += cross(p[i] - p[0], p[i + 1] - p[0]);        }        return 0.5 * fabs(area2);    }} hull;int main(){    int T;    Point p[2500],ch[2500];    scanf("%d",&T);    while(T--)    {        int n,pc = 0;        double area1 = 0.0;        scanf("%d",&n);        for(int i = 0; i < n; i++)        {            double w,h,j,rad;            Point o;            scanf("%lf %lf %lf %lf %lf",&o.x, &o.y, &w,&h,&j);            rad = -change(j);            p[pc++] = o + Rotate(Vector(-w/2,-h/2),rad);//求出木板的四個定點的座標            p[pc++] = o + Rotate(Vector( w/2,-h/2),rad);            p[pc++] = o + Rotate(Vector(-w/2, h/2),rad);            p[pc++] = o + Rotate(Vector( w/2, h/2),rad);            area1 += w * h;//累積木板的面積        }        int m = hull.convex(p,pc,ch); //求凸包;        double area2 = hull.PolygonArea(ch,m); //求面積        printf("%.1lf %%\n", area1 * 100 / area2);    }    return 0;}


 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.