[Astar2015]矩形面积解题报告

这是一个模板水题。。但是对于我来说却是第一道计算几何题,考场上写了两个小时终于写了出来,但是却因为最大值清错了挂掉了。真是蛋痛。

最小面积矩形至少有一边与凸包的一边重合,这个结论我第一感觉是对的。。但是当我屡WA不止时,我便渐渐开始怀疑它的正确性,然后发现我并不会证它。。

看了题解以后,发现还是很厉害的。

我们考虑如果把矩形卡住的是在矩形四条边上且不与端点重合的四个点,如图所示。那么我们分别过M和N作一条垂线,那么就出现了如图所示的两个夹角,不妨设之为∠1和∠2。那么矩形的面积S=MP*NQ*cos(∠1)*cos(∠2)。

然后我们将其旋转,假设我们转过一个角度之后,∠1变成了∠1+x,并且依然是这四个点卡住矩形,那么我们现在需要把S表示成关于x的函数。一个并不是比较显然的事情是∠1和∠2的改变量是相同的。这个可以自己手画一下就可以发现了。

那么现在S=MP*NQ*cos(∠1+x)*cos(∠2+x),这是一个不太好处理的积的形式,不过(题解)注意到如果将其积化和差的话可以把x赶到一边去,那么就比较好处理了。

S=MP?NQ?cos(∠1+∠2+2x)+cos(∠1?∠2)2

显然,∠1,∠2∈[0,π2)

∴∠1+∠2∈[0,π)

所以S|         ≠Smin,且显然x一定可以不为0.

|x=0

即必然可以将其旋转一定角度使得S减小。

所以最小面积包围矩形必然有一条边与凸包的边重合。

#include<cstdio>
#include<iostream>
using namespace std;
#include<cmath>
#include<algorithm>
#define eps 1e-8
struct XL{
    double x,y;
};
inline double cha(XL a,XL b){
    return a.x*b.y-a.y*b.x;
}
struct DS{
    double x,y;
    inline XL operator - (const DS & o) const{
        return (XL){x-o.x,y-o.y};
    }
    inline bool operator == (const DS & o)const{
        return x==o.x&&y==o.y;
    }
}dian[4005],stack1[4005],stack2[4005],tb[12005];
inline bool cmp1(DS a,DS b){
    if(a.x!=b.x)return a.x<b.x;
    else return a.y<b.y;
}
inline bool cmp2(DS a,DS b){
    if(a.x!=b.x)return a.x>b.x;
    else return a.y<b.y;
}
struct XS{
    double a,b,c;
};
inline double dis(DS dian,XS xian){
    return (xian.a*dian.x+xian.b*dian.y+xian.c)/sqrt(pow(xian.a,2.0)+pow(xian.b,2.0));
}
inline double queryk(DS a,DS b){
    if(a.x!=b.x)return (double)(b.y-a.y)/(b.x-a.x);
    else return 1e9;
}
inline XS makexian(DS a,DS b){
    return (XS){a.y-b.y,b.x-a.x,a.x*b.y-b.x*a.y};
}
int main(){
    int T,N,i,j,top1,top2,tot,k;
    XS nowxian,faxian;
    double Max,Min,tmp,ans;
    scanf("%d",&T);
    for(int Case=1;Case<=T;++Case){
        printf("Case #%d:\n",Case);
        scanf("%d",&N);
        N<<=2;
        for(i=0;i<N;++i)scanf("%lf%lf",&dian[i].x,&dian[i].y);

        //上凸壳
        sort(dian,dian+N,cmp1);
        N=unique(dian,dian+N)-dian;
        top1=1;
        stack1[0]=dian[0];
        for(i=1;i<N;++i){
            while(top1>1&&cha(stack1[top1-1]-stack1[top1-2],dian[i]-stack1[top1-1])>0)--top1;
            stack1[top1++]=dian[i];
        }
        /*cout<<"Up:";
        for(i=0;i<top1;++i)cout<<stack1[i].x<<","<<stack1[i].y<<" ";
        cout<<endl;*/
        //下凸壳
        top2=1;
        stack2[0]=dian[N-1];
        for(i=N-2;i>=0&&dian[i].x==dian[i+1].x;--i)stack2[top2++]=dian[i];
        for(;i>=0;--i){
            while(top2>1&&cha(stack2[top2-1]-stack2[top2-2],dian[i]-stack2[top2-1])>0)--top2;
            stack2[top2++]=dian[i];
        }
        /*cout<<"Down:";
        for(i=0;i<top2;++i)cout<<stack2[i].x<<‘,‘<<stack2[i].y<<" ";
        cout<<endl;*/
        //merge
        for(i=0;i<top1;++i)tb[i]=stack1[i];
        for(i=1;i+1<top2;++i)tb[top1+i-1]=stack2[i];
        tot=top1+top2-2;
        for(i=0;i<tot;++i)tb[tot+i]=tb[(tot<<1)+i]=tb[i];
        /*for(i=0;i<tot;++i)cout<<tb[i].x<<‘,‘<<tb[i].y<<‘ ‘;
        cout<<endl;*/
        //queryk
        ans=1e21;
        for(i=0,j=0;i<tot;++i){//枚举直线tb[i]-tb[i+1]
            //cout<<"---"<<tb[i].x<<","<<tb[i].y<<"->"<<tb[i+1].x<<‘,‘<<tb[i+1].y<<"----\n";
            nowxian=makexian(tb[i],tb[i+1]);
            while(fabs(dis(tb[j+1],nowxian))>=fabs(dis(tb[j],nowxian)))++j;
            //cout<<tb[j].x<<","<<tb[j].y<<":"<<fabs(dis(tb[j],nowxian))<<endl;
            faxian=(XS){nowxian.b,-nowxian.a,0};
            Max=-1e8,Min=1e8;
            for(k=0;k<tot;++k){
                tmp=dis(tb[k],faxian);
                Max=max(Max,tmp),Min=min(Min,tmp);
            }
            //cout<<"Max:"<<Max<<endl<<"Min:"<<Min<<endl;
            ans=min(ans,(Max-Min)*fabs(dis(tb[j],nowxian)));
            //cout<<"->"<<ans<<"!!!\n";
        }
        printf("%.f\n",(round(ans)));
    }
}

总结:

①以后不管做什么题一定要算清楚各种量的范围!(double什么的还是直接清个1e30什么的吧。。)

②遇到奇怪的积或和的形式,一定要试试和差化积!

③若证明最小值必在S中取到,我们可以反证最小值一定不会在CUS取到。

④遇到奇怪的结论的时候不要慌张,静下心来慢慢证就好了,看上去很麻烦的方法说不定其实很简单。

时间: 2024-08-06 20:07:04

[Astar2015]矩形面积解题报告的相关文章

解题报告:LeetCode Largest Rectangle in Histogram(计算最大矩形面积)

题目出处:https://leetcode.com/problems/largest-rectangle-in-histogram/题意描述:给定n个非负的整数,代表n个依次相邻的宽度为1的柱形的高,求这些柱形所能形成的最大的矩形面积. 解决思路:此题最直接最原始的做法就是扫描起点和终点,并随时更新最大面积,但是这样的做法的复杂度为O(n^2),显然会超时,这里就不再贴代码了. 于是我们需要考虑怎么将复杂度降下来,一种想法是在求面积之前进行预处理,将每个整数左右的第一个比当前位置矮的柱形的下标l

解题报告 之 HDU5301 Buildings

解题报告 之 HDU5301 Buildings Description Your current task is to make a ground plan for a residential building located in HZXJHS. So you must determine a way to split the floor building with walls to make apartments in the shape of a rectangle. Each buil

2014年秋季大学先修课考试 解题报告

A:细菌的战争 总时间限制:  1000ms 内存限制:  65536kB 描述 有两种细菌,一种是有害菌,繁殖能力很强,每小时会繁殖一倍:另一种是有益菌,繁殖能力较弱,每小时能繁殖百分之五.但在单位体积内,当有害菌数量超过一 百万时,多出的细菌会因为密度太大而迅速死亡,直到细菌数量下降到一百万.已知每个有益菌每小时能消灭一个有害菌.给定单位体积内有害菌和有益菌的初始数 量,请问多少小时后,有害菌将被有益菌消灭干净? 输入 输入的第一行为一个整数n,表示后边有n组数据.每组数据占一行,有两个整数

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

解题报告:LeetCode The Skyline Problem(画天际

题目出处:https://leetcode.com/submissions/detail/47013144/题意描述: 给定一系列矩形的左边坐标Li,右边坐标Ri,和高度Hi(其中Li按照从小到大的顺序排列).代表城市中一座座高楼.求这些矩形代表的高楼行成的天际线.天际线的定义为:在远处看这些所有的高楼时看到的轮廓. 数据输入: [ [L1, R1, H1], [Li, Ri, Hi]...]为元素类型为三维向量的向量,其中Li,Ri,Hi的含义见题意描述.且输入数据保证: 0 ≤ Li, Ri

JLOI2015 解题报告

那个嘛= =,虽说是JLOI的解题报告但还差第一题没写= =,就这样行啦 T2:[JLOI2015]城池攻占 首先这道题我们先考虑暴力,也就是每个点向父亲跑,我们考虑能否一起做,可以发现在同一个点的骑士可以用一个堆维护一起跳(因为没有改变优先级的操作)然后再用懒标记维护,我们可以直接用一个可合并堆来维护就可以啦 当然这道题用线段树,倍增都是可行的,就是空间比较拙计罢了,需要用一些奇奇怪怪的方法来干 CODE: 1 #include<cstdio> 2 #include<iostream&

Leetcode:Largest Rectangle in Histogram 最大矩形面积

Largest Rectangle in Histogram Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. Above is a histogram where width of each bar is 1, given heigh

常州培训 day5 解题报告

第一题:(贪心) 题目大意:给出N*M的矩形,要用正方形将它铺满(正方形之间不能重叠),相邻的正方形颜色不能相同,颜色用ABCD表示.要求从上到下从左到右字典序最小. N,M<=100 解题过程: 1.首先感觉是能放就尽可能使正方形边长大,但是很明显有反例(见图A) 2.然后想到从上到下从左到右,依次检查,如果还没被铺上,那么就先铺上1*1的X,然后检查它右边能填什么,如果他右边能填的比它大(Y),那么就把1*1的改成尽可能大,如果他右边的比它小,那么它只要放1*1的X,然后右边放尽可能大的Y.

poj分类解题报告索引

图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Journey poj1724 - ROADS(邻接表+DFS) BFS poj3278 - Catch That Cow(空间BFS) poj2251 - Dungeon Master(空间BFS) poj3414 - Pots poj1915 - Knight Moves poj3126 - Prim