HDU5251矩形面积(凸包+旋转卡壳求最小矩形覆盖)

题目链接:传送门 

题意:

给定n个矩形,求一个面积最小的矩形将这些矩形全部覆盖住。

分析:

首先求一个凸包将这些点给覆盖住,就转换成求一个面积最小的矩形将凸包覆盖住。很明显矩形的一条边肯定是凸包的一条边。因此我们枚举凸包的边,然后旋转卡壳求最左边,最右边,最上边的那个三个点那么就可以确定这个矩形了。剩下的就是用几何知识来求这个矩形的面积了。

根据最上面的那个点与我们枚举的那个边,通过叉积可以确定矩形的高,然后根据最左边的点与最右边的点和我们枚举的边可以确定矩形的底,知道高和底就可以求矩形的面积了。

代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;

typedef long long LL;

const double eps = 1e-10;

const int maxn = 4e3+10;

const double inf = 1e17;

int dcmp(double x){
    if(fabs(x)<eps) return 0;
    if(x>0) return 1;
    return -1;
}

struct point{
    double x,y;
    bool operator <(const struct point &tmp)const{
        if(dcmp(x-tmp.x)==0) return dcmp(y-tmp.y)<0;
        return dcmp(x-tmp.x)<0;
    }
    bool operator == (const struct point &tmp)const{
        return dcmp(x-tmp.x)==0&&dcmp(y-tmp.y)==0;
    }
}p[maxn],st[maxn];

double Cross(point a,point b,point c){
    return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}

double dot(point a,point b,point c){//点积
    double s1=b.x-a.x;
    double t1=b.y-a.y;
    double s2=c.x-a.x;
    double t2=c.y-a.y;
    return s1*s2+t1*t2;
}

int ConvexHull(point *p,int n,point *st){
    sort(p,p+n);
    n=unique(p,p+n)-p;
    int m=0;
    for(int i=0; i<n; i++) {
        while(m>1&&Cross(st[m-2],p[i],st[m-1])<=0) m--;
        st[m++]=p[i];
    }
    int k=m;
    for(int i=n-2; i>=0; i--){
        while(m>k&&Cross(st[m-2],p[i],st[m-1])<=0)m--;
        st[m++]=p[i];
    }
    if(n>1) m--;
    return m;
}

double dist(point a,point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double rotating_calipers(point *p,int n){
    int R=1,U=1,L;
    double ans = 10000000000000;
    p[n]=p[0];
    for(int i=0;i<n;i++){
        while(dcmp(Cross(p[i],p[i+1],p[U+1])-Cross(p[i],p[i+1],p[U]))<=0) U=(U+1)%n;//最上面一点
        while(dcmp(dot(p[i],p[i+1],p[R+1])-dot(p[i],p[i+1],p[R]))>0) R=(R+1)%n;//最右一点
        if(i==0) L=R;
        while(dcmp(dot(p[i],p[i+1],p[L+1])-dot(p[i],p[i+1],p[L]))<=0) L=(L+1)%n;//最左一点
        double d=dist(p[i],p[i+1])*dist(p[i],p[i+1]);
        double area=fabs(Cross(p[i],p[i+1],p[U]))*//求面积
            fabs(dot(p[i],p[i+1],p[R])-dot(p[i],p[i+1],p[L]))/d;
        if(area<ans) ans = area;
    }
    return ans;
}

int main(){
    int n,t,cas=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        n*=4;
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        int m = ConvexHull(p,n,st);
        double ans;
        if(m<3) ans=0;
        else ans = rotating_calipers(st,m);
        LL tmp = ans+0.5;
        printf("Case #%d:\n%I64d\n",cas++,tmp);
    }
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值