[Astar2015]矩形面积解题报告
来源:互联网 发布:chrome淘宝比价插件 编辑:程序博客网 时间:2024/06/06 01:09
这是一个模板水题。。但是对于我来说却是第一道计算几何题,考场上写了两个小时终于写了出来,但是却因为最大值清错了挂掉了。真是蛋痛。
最小面积矩形至少有一边与凸包的一边重合,这个结论我第一感觉是对的。。但是当我屡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减小。
所以最小面积包围矩形必然有一条边与凸包的边重合。
#include<cstdio>#include<iostream>using namespace std;#include<cmath>#include<algorithm>#define eps 1e-8struct 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中取到,我们可以反证最小值一定不会在
④遇到奇怪的结论的时候不要慌张,静下心来慢慢证就好了,看上去很麻烦的方法说不定其实很简单。
0 0
- [Astar2015]矩形面积解题报告
- 【解题报告】嵌套矩形
- codevs1249 多边形面积 解题报告
- POJ 1005(圆的面积) 解题报告
- 【算法解题报告】求三角形的面积
- POJ 3348 凸包面积 解题报告
- Poj 1654 Area 计算面积 解题报告
- 洛谷 1318 积水面积 模拟 解题报告
- 【LintCode】454.矩阵面积(入门)解题报告
- hihocoder 1040 矩形判断解题报告
- 矩形面积
- 线段树——HDU1255 覆盖的面积解题报告
- 【Jason's_ACM_解题报告】矩形嵌套(NYOJ16)
- 【ACM菜逼解题报告】矩形嵌套(NYOJ16)
- Leetcode 84. Largest Rectangle in Histogram 最大矩形 解题报告
- Leetcode 85. Maximal Rectangle 最大矩形 解题报告
- Leetcode 391. Perfect Rectangle 完美矩形 解题报告
- 【解题报告】POJ1151 扫描线+线段树(矩形求并)
- Linux 下最为人熟知的归档/压缩工具
- POJ 3253 Fence Repair
- 微信仿制的时候常用的抓包工具
- css3基本选择器
- Skinned Mesh原理解析和一个最简单的实现示例
- [Astar2015]矩形面积解题报告
- 使用Hadoop ACL 控制访问权限
- h5播放音乐
- Nim教程翻译(二)
- 4-1
- vim保存并退出
- css3属性选择器
- UNP chapter3 习题3.3
- 【HAOI 2007】【BZOJ 1053】反素数ant