UVa10652 - Board Wrapping(凸包+S+向量旋转)

题目链接

简介:凸包

分析:简介就已经邪泄露了正解

tip

这道题求坐标是一个难点
有一个很好的方法
我们知道点+向量=点
所以我们可以先算出中点到达每块木板的四个点的方向向量,点的坐标直接用中点坐标加上方向向量即可

a=-torad(j);                                  //变成弧度制 
node o=node(x,y);                             //顺时针转动,点+向量=点 
po[++cnt]=o+rotate(node(-w/2,-h/2),a);                 //左下 
po[++cnt]=o+rotate(node(-w/2,h/2),a);                  //左上 
po[++cnt]=o+rotate(node(w/2,h/2),a);                   //右上 
po[++cnt]=o+rotate(node(w/2,-h/2),a);                  //右下 
area1+=w*h;

在计算面积的时候,一定要把坐标写准了

double SS(int n)
{
    double ans=0;
    for (int i=2;i<=n;i++)
        ans+=Cross(po[sta[i]]-po[sta[1]],po[sta[i+1]]-po[sta[1]]);
    return fabs(ans)/2;
}
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const double Pi=acos(-1.0);
const double eps=1e-8;
const int N=3000;
int n,sta[N];
struct node{
    double x,y;
    node (double xx=0,double yy=0)
    {
        x=xx;y=yy;
    }
};
node po[N];

node operator + (const node &a,const node &b){return node(a.x+b.x,a.y+b.y);}
node operator - (const node &a,const node &b){return node(a.x-b.x,a.y-b.y);}
node operator * (const node &a,const double &b){return node(a.x*b,a.y*b);}
node operator / (const node &a,const double &b){return node(a.x/b,a.y/b);}
bool operator < (const node &a,const node &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
bool operator == (const node &a,const node &b){return a.x==b.x&&a.y==b.y;}

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

double torad(double n)
{
    return n*Pi/180;
}

double Cross(node x,node y){return x.x*y.y-x.y*y.x;}
double Dot(node x,node y){return x.x*y.x+x.y*y.y;}

node rotate(node x,double a)
{
    return node(x.x*cos(a)-x.y*sin(a),x.x*sin(a)+x.y*cos(a));
}

int TuB(int n)
{
    int top=0;
    sort(po+1,po+1+n);
    for (int i=1;i<=n;i++)
    {
        while (top>1&&dcmp( Cross( po[sta[top]]-po[sta[top-1]] , po[i]-po[sta[top-1]] ) )<=0) top--;     //顺时针转动不合法 
        sta[++top]=i;
    }
    int k=top;
    for (int i=n-1;i>=1;i--)
    {
        while (top>k&&dcmp( Cross( po[sta[top]]-po[sta[top-1]] , po[i]-po[sta[top-1]] ))<=0) top--;
        sta[++top]=i;
    }
    if (n>1) top--;
    return top;
}

double SS(int n)
{
    double ans=0;
    for (int i=2;i<=n;i++)
        ans+=Cross(po[sta[i]]-po[sta[1]],po[sta[i+1]]-po[sta[1]]);
    return fabs(ans)/2;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        double x,y,w,h,j,a;
        double area1=0;
        scanf("%d",&n);
        int cnt=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y,&w,&h,&j);
            a=-torad(j);                                  //变成弧度制 
            node o=node(x,y);                             //顺时针转动,点+向量=点 
            po[++cnt]=o+rotate(node(-w/2,-h/2),a);                 //左下 
            po[++cnt]=o+rotate(node(-w/2,h/2),a);                  //左上 
            po[++cnt]=o+rotate(node(w/2,h/2),a);                   //右上 
            po[++cnt]=o+rotate(node(w/2,-h/2),a);                  //右下 
            area1+=w*h;
        }     

        int m=TuB(cnt);

        double area2=SS(m);
        printf("%.1lf %%\n",area1*100/area2);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值