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 | ;

  • 相关阅读:
    mysql随笔 -- 基本sql语句
    jdbc驱动底层代码(通过控制器查询数据库的数据)
    项目实战:数据库,服务器,浏览器的登录页面的实现
    JSP随笔
    Session的学习
    servlet请求转发
    Servlet的流程总结
    collection 知识点3
    linux虚拟机,Centos7部署django项目
    python高级函数以及文件操作
  • 原文地址:https://www.cnblogs.com/get-an-AC-everyday/p/4545357.html
Copyright © 2011-2022 走看看