zoukankan      html  css  js  c++  java
  • 2015baidu复赛 矩形面积(包凸 && ps:附quickhull模板)

    矩形面积

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 168    Accepted Submission(s): 93


    Problem Description
    小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少。
     
    Input
    第一行一个正整数 T,代表测试数据组数(1T20),接下来 T 组测试数据。

    每组测试数据占若干行,第一行一个正整数 N(1N<1000),代表矩形的数量。接下来 N 行,每行 8 个整数x1,y1,x2,y2,x3,y3,x4,y4,代表矩形的四个点坐标,坐标绝对值不会超过10000。
     
    Output
    对于每组测试数据,输出两行:

    第一行输出"Case #i:",i 代表第 i 组测试数据。
    第二行包含1 个数字,代表面积最小的矩形的面积,结果保留到整数位。
     
    Sample Input
    2 2 5 10 5 8 3 10 3 8 8 8 8 6 7 8 7 6 1 0 0 2 2 2 0 0 2
     
    Sample Output
    Case #1: 17 Case #2: 4
     
    Source
     
     1 #include<stdio.h>
     2 #include<set>
     3 #include<algorithm>
     4 #include<string.h>
     5 #define one first
     6 #define two second
     7 #define zero 1e-12
     8 #define sgn(x) (fabs(x)<zero?0:(x>0?1:-1))
     9 #define shadow(a,b,c)  ((b.one-a.one)*(c.one-a.one)+(b.two-a.two)*(c.two-a.two))/sqrt((b.one-a.one)*(b.one-a.one)+(b.two-a.two)*(b.two-a.two))
    10 #define cross(a,b,c) ((b.one-a.one)*(c.two-a.two)-(b.two-a.two)*(c.one-a.one))
    11 #define cmp(a,b) (a.one<b.one || sgn(a.one-b.one)==0 && a.two<b.two)
    12 const int M = 5000 , inf = 0x3f3f3f3f ;
    13 int n ;
    14 std::pair<double , double > p[M] ;
    15 double s[M];
    16 std::pair<double , double > jk[M] ;
    17 int tot ;
    18 
    19 void hull(int l,int r, std::pair<double , double>a,std::pair<double , double> b){
    20     int x=l,i=l-1,j=r+1,k;
    21     for (k=l;k<=r;k++){
    22         double temp=sgn(s[x]-s[k]);
    23         if (temp<0 || temp==0 && cmp(p[x],p[k])) x=k;
    24     }
    25     std::pair<double , double> y=p[x];
    26     for (k=l;k<=r;k++){
    27         s[++i]=cross(p[k],a,y);
    28         if (sgn(s[i])>0) std::swap(p[i],p[k]); else i--;
    29     }
    30     for (k=r;k>=l;k--){
    31         s[--j]=cross(p[k],y,b);
    32         if (sgn(s[j])>0) std::swap(p[j],p[k]); else j++;
    33     }
    34     if (l<=i) hull(l,i,a,y);
    35     jk[tot ++] = y ;
    36     if (j<=r) hull(j,r,y,b);
    37 }
    38 
    39 void solve ()
    40 {
    41     double l , r , h , sum = inf ;
    42     double d = 0 ;
    43     for (int i = 1 ; i <= tot ; i ++) {
    44         d = (jk[i].one - jk[i - 1].one) * (jk[i].one - jk[i - 1].one) + (jk[i].two - jk[i - 1].two) * (jk[i].two - jk[i - 1].two) ;
    45         l = 0 , r = sqrt (d) ;
    46         h = 0 ;
    47         for (int j = 1 ; j <= n ; j ++) {
    48             if (p[j] != jk[i] && p[j] != jk[i - 1]) {
    49                 h = std::max (h , fabs (cross (jk[i] , jk[i - 1] , p[j])) / sqrt(d)) ;
    50                 l = std::min (l , shadow (jk[i] , jk[i - 1] , p[j])) ;
    51                 r = std::max (r , shadow (jk[i] , jk[i - 1] , p[j])) ;
    52             }
    53         }
    54         sum = std::min (sum , (r - l) * h) ;
    55     }
    56     printf ("%.0f
    " , sum) ;
    57 }
    58 
    59 int main(){
    60    //freopen ("a.txt" , "r" , stdin) ;
    61    int T , cas = 1 ;
    62    scanf ("%d" , &T) ;
    63    while (T --) {
    64         printf ("Case #%d:
    " , cas ++) ;
    65         memset (s , 0 , sizeof(s)) ;
    66         int i , x=0 ;
    67         tot = 0 ;
    68         scanf("%d",&n);
    69         n *= 4 ;
    70         for (i=1;i<=n;i++){
    71             scanf("%lf%lf",&p[i].one,&p[i].two);
    72             if (x==0 || cmp(p[i],p[x])) x=i;
    73         }
    74         std::swap(p[1],p[x]);
    75         jk[tot ++] = p[1] ;
    76         hull(2,n,p[1],p[1]);
    77         jk[tot] = jk[0] ;
    78         solve () ;
    79     }
    80     return 0;
    81 }
    View Code

     用这种做法,首先要明白最小的覆盖矩形的其中一边必定是和壳重合。

    所以我们只要求出壳,并枚举壳上的每条边,并计算出在它上生成的最小矩阵面积。然后找出其中最小的就好了。

    复杂度((4*n)^2);

     1 #include<bits/stdc++.h>
     2 #define one first
     3 #define two second
     4 #define eps 1e-12
     5 #define sgn(x) (x<eps?0:(x>0?1:-1))
     6 #define cross(a,b,c) ((b.one-a.one)*(c.two-a.two)-(b.two-a.two)*(c.one-a.one))
     7 #define cmp(a,b) (a.one<b.one || sgn(a.one-b.one)==0 && a.two<b.two)
     8 const int M = 1e5 , inf = 0x3f3f3f3f ;
     9 int n ;
    10 std::pair<double , double> p [M] ;
    11 int s[M] ;
    12 std::pair<double , double> jk[M] ;
    13 int tot = 0 ;
    14 
    15 void hull (int l , int r , std::pair<double , double> a , std::pair<double , double> b)
    16 {
    17     //printf ("(%d , %d)
    " , l , r ) ;
    18     int x = l , _l = l - 1 , _r = r + 1 ;
    19     for (int i = l ; i <= r ; i ++) {
    20         int tmp = sgn(s[i]-s[x]) ;
    21         if (tmp > 0 || tmp == 0 && cmp(p[x],p[i])) x = i ;
    22     }
    23     for (int i = l ; i <= r ; i ++) {
    24         s[++ _l] = cross(p[i],a,p[x]) ;
    25         if (sgn(s[_l]) > 0) std::swap (p[i] , p[_l]) ; else _l -- ;
    26     }
    27     for (int i = r ; i >= l ; i --) {
    28         s[-- _r] = cross(p[i],p[x],b) ;
    29         if (sgn(s[_r]) > 0) std::swap (p[i] , p[_r]) ; else _r ++ ;
    30     }
    31     if (l <= _l)hull (l , _l , a , p[x]) ;
    32     jk[tot ++] = p[x] ;
    33     if (_r <= r)hull (_r , r , p[x] , b) ;
    34 }
    35 
    36 int main ()
    37 {
    38    // freopen ("a.txt" , "r" , stdin ) ;
    39     memset (s , 0 , sizeof(s)) ;
    40     scanf ("%d" , &n) ; //printf ("n = %d
    " , n ) ;
    41     int x = -1 ;
    42     for (int i = 1 ; i <= n ; i ++) {
    43         scanf ("%lf%lf" , &p[i].one , &p[i].two) ;
    44         if (x == -1 || cmp (p[i] , p[x])) x = i ;
    45     }
    46     std::swap (p[x] , p[1]) ;
    47     jk[tot ++] = p[1] ;
    48     hull (2 , n , p[1] , p[1]) ;
    49     for (int i = 0 ; i < tot ; i ++) printf ("(%.4f , %.4f)
    " , jk[i].one , jk[i].two) ;
    50     return 0 ;
    51 }
    92_quickhull

    要了解这个算法的思路,先去维基上看看动态演示http://en.wikipedia.org/wiki/Quickhull

    然后你需要知道叉积(叉积 "X" 表示):已知两个向量 a = (x1 , y1) , b = (x2 , y2);

    叉积:a X b = x1 * y2 - x2 * y1 ;

    点积:a * b = x1 * x2 + y1 * y2 ;

    两个向量间的的夹角:a * b = |a| * |b| * cosθ ;

    那么这两个向量 构成的三角形面积 S = 1/2 * abs (a X b) ,

    还有 a X b = - b X a ;

    知道以上这两个概念,就看的动quickhull了。

    就这道题而言,你还需要知道,  a 在 b 上的投影求法a * b / | b | ;

  • 相关阅读:
    selenium 8大元素定位方法
    selenium环境安装及简单使用
    Python json序列化和反序列化
    pytest使用allure生成测试报告
    Windows10下JDK15的安装教程
    Ansible:服务器巡检_3、Windows 平台巡检
    转载:shell中各种括号的作用详解()、(())、[]、[[]]、{}(推荐)
    Tips: Linux 中 当形参名称是 变量时,如何取出全部的实参
    Python 问题记录:XXX.whl is not a supported wheel on this platform.
    Ansible:服务器巡检_2、Linux 服务器巡检脚本
  • 原文地址:https://www.cnblogs.com/get-an-AC-everyday/p/4545357.html
Copyright © 2011-2022 走看看