2015百度之星初赛(1)1006 旋转卡壳

矩形面积

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


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
 
题目实际上就是给你很多的点,要求最小的外接矩形。(面积最小),凸包,旋转卡壳即可,算是模板题,UVA10137是差不多的题目。
代码:
//旋转卡壳,百度之星初赛最后一题
 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
 
struct point
{
    double x,y;
}p[10005];
 
int ans[10005],st[10005],stop,cnt,n;
 
int DB (double d){
    if (fabs(d)<1e-8)
        return 0;
    return d>0?1:-1;
}
double cross (point a,point b,point c){
    return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
double dot(point a,point b,point c){
    return (a.x-c.x)*(b.x-c.x)+(a.y-c.y)*(b.y-c.y);
}
bool cmp(point A,point B){
    if(A.y<B.y) return true;
    else if(A.y==B.y){
        if(A.x<B.x)return true;
    }
    return false;
}
 
void forTU(){
    stop=cnt=0;
    st[stop++]=0; st[stop++]=1;
    for(int i=2;i<n;i++){
        while(stop>1&&cross(p[i],p[st[stop-1]],p[st[stop-2]])>=0) stop--;
        st[stop++]=i;
    }
    for(int i=0;i<stop;i++)
    ans[cnt++]=st[i];
    stop=0; st[stop++]=n-1; st[stop++]=n-2;
    for(int i=n-3;i>=0;i--){
        while(stop>1&&cross(p[i],p[st[stop-1]],p[st[stop-2]])>=0) stop--;
        st[stop++]=i;
    }
    for(int i=1;i<stop;i++){
        ans[cnt++]=st[i];
    }
}
 
double roating(){
    cnt--;
    if(n<3) return 0;
    int i,m=1,q=1,r;
    double anst=1e10,a,b,c;
    for(i=0;i<cnt;i++){
        while (DB(cross(p[ans[(i+1)]],p[ans[(m+1)]],p[ans[i]])-cross(p[ans[(i+1)]],p[ans[m]],p[ans[i]])) >0)
        m=(m+1)%cnt;
        while (DB(dot(p[ans[(q+1)]],p[ans[(i+1)]],p[ans[i]])-dot(p[ans[q]],p[ans[(i+1)]],p[ans[i]])) >0)
        q=(q+1)%cnt;
        if (i==0)
        r=q;
        while(DB(dot(p[ans[(r+1)]],p[ans[(i+1)]],p[ans[i]])-dot(p[ans[r]],p[ans[(i+1)]],p[ans[i]])) <= 0)
        r=(r+1)%cnt;
        a=cross(p[ans[(i+1)]],p[ans[m]],p[ans[i]]);
        b=dot(p[ans[q]],p[ans[(i+1)]],p[ans[i]])-dot(p[ans[r]],p[ans[(i+1)]],p[ans[i]]);
        c=dot(p[ans[(i+1)]],p[ans[(i+1)]],p[ans[i]]);
        anst=min(anst,a*b/c);
    }
    return anst;
}
 
int main (){ 
int number;
cin>>number;
for(int numm=1;numm<=number;numm++)
     {	 cin>>n;
   		  n*=4;
   		  cout<<"Case #"<<numm<<":"<<endl;
        for (int i=0;i<n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
        sort(p,p+n,cmp);  
        forTU(); 
        printf("%.0lf\n",roating()); 
    } 
    return 0; 
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值