2015年百度之星初赛(1) --- F 矩形面积

矩形面积

Problem Description

小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少。

Input

第一行一个正整数 T,代表测试数据组数($1 \leq T \leq 20$),接下来 T 组测试数据。

每组测试数据占若干行,第一行一个正整数 $N(1 \leq N < \leq 1000)$,代表矩形的数量。接下来 N 行,每行 8 个整数$x_1, y_1, x_2, y_2, x_3, y_3, x_4, y_4$,代表矩形的四个点坐标,坐标绝对值不会超过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

Problem‘s Link:   http://acm.hdu.edu.cn/showproblem.php?pid=5251


Mean:

analyse:

把n个矩形的点输入多边形寻找最小覆盖面积矩形的模版代码中就OK,网上套的模板。

Time complexity: O(n)

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-05-31-23.18
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;
const double eps = 1e-8;
const int N = 4004;
int sign(double d)
{
    return d < -eps ? -1 : (d > eps);
}
struct point
{
    double x, y;
    point operator-(point d){
        point dd;
        dd.x = this->x - d.x;
        dd.y = this->y - d.y;
        return dd;
    }
    point operator+(point d){
        point dd;
        dd.x = this->x + d.x;
        dd.y = this->y + d.y;
        return dd;
    }
    void read(){ scanf("%lf%lf", &x, &y); }
}ps[N];

int n, cn;

double dist(point d1, point d2)
{
    return sqrt(pow(d1.x - d2.x, 2.0) + pow(d1.y - d2.y, 2.0));
}

double dist2(point d1, point d2)
{
    return pow(d1.x - d2.x, 2.0) + pow(d1.y - d2.y, 2.0);
}

bool cmp(point d1, point d2)
{
    return d1.y < d2.y || (d1.y == d2.y && d1.x < d2.x);
}

//st1-->ed1叉乘st2-->ed2的值
double xmul(point st1, point ed1, point st2, point ed2)
{
    return (ed1.x - st1.x) * (ed2.y - st2.y) - (ed1.y - st1.y) * (ed2.x - st2.x);
}

double dmul(point st1, point ed1, point st2, point ed2)
{
    return (ed1.x - st1.x) * (ed2.x - st2.x) + (ed1.y - st1.y) * (ed2.y - st2.y);
}

//多边形类
struct poly
{
    static const int N = 50005; //点数的最大值
    point ps[N+5]; //逆时针存储多边形的点,[0,pn-1]存储点
    int pn;  //点数
    poly() { pn = 0; }
    //加进一个点
    void push(point tp)
    {
        ps[pn++] = tp;
    }
    //第k个位置
    int trim(int k)
    {
        return (k+pn)%pn;
    }
    void clear(){ pn = 0; }
};

//返回含有n个点的点集ps的凸包
poly graham(point* ps, int n)
{
    std::sort(ps, ps + n, cmp);
    poly ans;
    if(n <= 2){
        for(int i = 0; i < n; i++)
        {
            ans.push(ps[i]);
        }
        return ans;
    }
    ans.push(ps[0]);
    ans.push(ps[1]);
    point* tps = ans.ps;
    int top = -1;
    tps[++top] = ps[0];
    tps[++top] = ps[1];
    for(int i = 2; i < n; i++)
    {
        while(top > 0 && xmul(tps[top - 1], tps[top], tps[top - 1], ps[i]) <= 0) top--;
        tps[++top] = ps[i];
    }

    int tmp = top;  //注意要赋值给tmp!

    for(int i = n - 2; i >= 0; i--)
    {
        while(top > tmp && xmul(tps[top - 1], tps[top], tps[top - 1], ps[i]) <= 0) top--;
        tps[++top] = ps[i];
    }
    ans.pn = top;
    return ans;
}
//求点p到st->ed的垂足,列参数方程
point getRoot(point p, point st, point ed)
{
    point ans;
    double u=((ed.x-st.x)*(ed.x-st.x)+(ed.y-st.y)*(ed.y-st.y));
    u = ((ed.x-st.x)*(ed.x-p.x)+(ed.y-st.y)*(ed.y-p.y))/u;
    ans.x = u*st.x+(1-u)*ed.x;
    ans.y = u*st.y+(1-u)*ed.y;
    return ans;
}

//next为直线(st,ed)上的点,返回next沿(st,ed)右手垂直方向延伸l之后的点
point change(point st, point ed, point next, double l)
{
    point dd;
    dd.x = -(ed - st).y;
    dd.y = (ed - st).x;
    double len = sqrt(dd.x * dd.x + dd.y * dd.y);
    dd.x /= len, dd.y /= len;
    dd.x *= l, dd.y *= l;
    dd = dd + next;
    return dd;
}

//求含n个点的点集ps的最小面积矩形,并把结果放在ds(ds为一个长度是4的数组即可,ds中的点是逆时针的)中,并返回这个最小面积。
double getMinAreaRect(point* ps, int n, point* ds)
{
    int cn, i;
    double ans;
    point* con;
    poly tpoly = graham(ps, n);
    con = tpoly.ps;
    cn = tpoly.pn;
    if(cn <= 2)
    {
        ds[0] = con[0]; ds[1] = con[1];
        ds[2] = con[1]; ds[3] = con[0];
        ans=0;
    }
    else
    {
        int  l, r, u;
        double tmp, len;
        con[cn] = con[0];
        ans = 1e40;
        l = i = 0;
        while(dmul(con[i], con[i+1], con[i], con[l])
            >= dmul(con[i], con[i+1], con[i], con[(l-1+cn)%cn]))
        {
            l = (l-1+cn)%cn;
        }
        for(r=u=i = 0; i < cn; i++){
            while(xmul(con[i], con[i+1], con[i], con[u])
                <= xmul(con[i], con[i+1], con[i], con[(u+1)%cn]))
            {
                u = (u+1)%cn;
            }
            while(dmul(con[i], con[i+1], con[i], con[r])
                <= dmul(con[i], con[i+1], con[i], con[(r+1)%cn]))
            {
                r = (r+1)%cn;
            }
            while(dmul(con[i], con[i+1], con[i], con[l])
                >= dmul(con[i], con[i+1], con[i], con[(l+1)%cn]))
            {
                l = (l+1)%cn;
            }
            tmp = dmul(con[i], con[i+1], con[i], con[r]) - dmul(con[i], con[i+1], con[i], con[l]);
            tmp *= xmul(con[i], con[i+1], con[i], con[u]);
            tmp /= dist2(con[i], con[i+1]);
            len = xmul(con[i], con[i+1], con[i], con[u])/dist(con[i], con[i+1]);
            if(sign(tmp - ans) < 0)
            {
                ans = tmp;
                ds[0] = getRoot(con[l], con[i], con[i+1]);
                ds[1] = getRoot(con[r], con[i+1], con[i]);
                ds[2] = change(con[i], con[i+1], ds[1], len);
                ds[3] = change(con[i], con[i+1], ds[0], len);
            }
        }
    }
    return ans+eps;
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int Cas = 1; Cas <=t; ++Cas)
    {
        printf("Case #%d:\n",Cas);
        int num = 0;
        scanf("%d",&num);
        for(int i = 0; i < num ; ++i)
        {
            ps[i*4+0].read();
            ps[i*4+1].read();
            ps[i*4+2].read();
            ps[i*4+3].read();
        }
        struct point ds[4];
        double ans = getMinAreaRect(ps,num*4,ds);
        printf("%.0lf\n",ans);
    }
    return 0;
}

时间: 2024-10-13 11:09:16

2015年百度之星初赛(1) --- F 矩形面积的相关文章

2015年百度之星初赛(1) --- D KPI

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 170    Accepted Submission(s): 59 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的KP

2015年百度之星初赛(1) --- C 序列变换

序列变换 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 158    Accepted Submission(s): 83 Problem Description 给定序列$A = \{A_1, A_2,...,A_n\}$, 要求改变序列A中的某些元素,形成一个严格单调的序列B(严格单调的定义为:$B_i < B_{i+1}, 1 \

2015年百度之星初赛(1) --- B 找连续数

找连续数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 179    Accepted Submission(s): 65 Problem Description 小度熊拿到了一个无序的数组,对于这个数组,小度熊想知道是否能找到一个k 的区间,里面的 k 个数字排完序后是连续的. 现在小度熊增加题目难度,他不想知道是否有这样的 k 的区

2015年百度之星初赛(1) --- 超级赛亚ACMer

超级赛亚ACMer Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 百小度是一个ACMer,也是一个超级赛亚人,每个ACMer都有一个战斗力,包括百小度.?所谓超级赛亚人的定义,是说如果在对抗中刚好接近极限状态,那就会激发斗志,实力提升.? 具体来说,就是百小度现在要接受一些ACMer的挑战了,这些ACMer有n个人,第i个人的战斗力是a[i]

数学 2015百度之星初赛2 HDOJ 5255 魔法因子

题目传送门 1 /* 2 数学:不会写,学习一下这种解题方式:) 3 思路:设符合条件的数的最高位是h,最低位是l,中间不变的部分为mid,由题意可得到下面的公式(这里对X乘上1e6用a表示,b表示1e6) 4 (h*power+l+mid)*a = (l*power+h+mid)*b 5 可推得:mid = ((h*power+l) * a - (l*power+h) * b) / (a - b); 6 所以可以枚举h,l然后求mid,注意mid的最低位一定是0,因为留出最低位加l或者h 7

LIS 2015百度之星初赛2 HDOJ 5256 序列变换

题目传送门 1 /* 2 LIS(非严格):首先我想到了LIS,然而总觉得有点不对:每个数先减去它的下标,防止下面的情况发生:(转载) 3 加入序列是1,2,2,2,3,这样求上升子序列是3,也就是要修改2个,但是中间的两个2,变化范围又不能超过(1,3) 4 那么这样求的也就不对,但是减掉之后,相当于给中间重复的数留下了修改的空间 5 解释下为什么可以减而保持正确性:因为题目所求时严格递增,假设是2,3, 4,那么变成1, 1, 1,所以在LIS里非严格递增就可以了 6 这也是为什么要在upp

二分搜索 2015百度之星初赛1 1003 序列变换

题目传送门 1 /* 2 二分搜索:在0-1e6的范围找到最小的max (ai - bi),也就是使得p + 1 <= a[i] + c or a[i] - c 3 比赛时以为是贪心,榨干智商也想不出来:( 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <iostream> 10 using

二分查找 2015百度之星初赛1 1001 超级赛亚ACMer

题目传送门 1 /* 2 二分找到不大于m的最大的数,记做p,只要a[p] + k <= a[p+1]就继续 3 注意:特判一下当没有比m小的数的情况:) 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 11 typedef long long ll; 12 13 const

BFS 2015百度之星初赛2 HDOJ 5254 棋盘占领

题目传送门 1 /* 2 BFS:先把1的入队,每个1和它相邻的组合后看看能不能使0变1,若有则添加入队,change函数返回改变了多少个0 3 注意:结果还要加上原来占领的 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <vector> 10 #include <queue> 11