飞机的碎片
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1276 Accepted Submission(s): 187
Problem Description
一架飞机不幸在某海洋上失事,海面上漂浮着一架飞机的一些碎片…… 幸好有卫星把这些碎片拍下来了,可以大致让我们确定一块搜索的区域来确定失事飞机的位置。 为了更好地进行搜救,节约成本,需要在海上划出一块周长尽可能小的区域进行巡逻式的搜救。但是由于技术问题,巡逻的区域只能是矩形。现给出这些碎片的相对位置,请告知这块巡逻区域的周长(请务必保留小数点后6位数字) 由于雷达扫描到的碎片相对于广阔的海洋实在太小,可以用极小的点来代替它。
Input
输入包含多组测试用例,每组测试用例的第一行包含一个整数N(3≤N≤10 000),表示碎片在海洋里的数量,接下去N行中的每行都有两个整数Xi和Yi(0 ≤ Xi, Yi ≤ 10 000),表示碎片的坐标。每个碎片的坐标都不同,并且所有的碎片都不在同一直线上。
Output
每一个测试用例,输出一行包含一个实数,一个矩形区域的最小周长。注意矩形的边缘不需要与坐标轴平行。
Sample Input
3 0 0 1 0 0 1
Sample Output
4.000000
为了做这题,我不得不花大约半天时间学习旋转卡壳的思想,然后得到了以下搓到暴的代码。希望大神们给个好的模板地址啥的
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define maxn 11000
#define maxm 10000+10
#define mod 1000000007
#define eps 1e-7
#define PI acos(-1.0)
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scanll2(n,m) scanf("%I64d%I64d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
#define outll(n) printf("%I64d\n",n)
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct Point
{
double x,y;
Point(double xx,double yy)
{
x=xx;
y=yy;
}
Point()
{
x=0;
y=0;
}
void in()
{
scanf("%lf%lf",&x,&y);
}
}a[maxn],p[maxn];
typedef Point Vector;
Vector operator+(Vector A,Vector B)
{
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator-(Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator*(Vector A,double p)
{
return Vector(A.x*p,A.y*p);
}
Vector operator/(Vector A,double p)
{
return Vector(A.x/p,A.y/p);
}
Vector operator*(double p,Vector A)
{
return Vector(A.x*p,A.y*p);
}
Vector operator/(double p,Vector A)
{
return Vector(A.x/p,A.y/p);
}
bool operator<(const Point& a,const Point& b)
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int dcmp(double x)
{
if(fabs(x)<eps)
{
return 0;
}
else
return x<0?-1:1;
}
bool operator==(const Point& a,const Point& b)
{
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Vector a,Vector b)
{
//计算点积
return a.x*b.x+a.y*b.y;
}
double Cross(Vector a,Vector b)
{
//计算叉积
return a.x*b.y-a.y*b.x;
}
double Length(Vector a)
{
//计算长度
return sqrt(Dot(a,a));
}
double Angle(Vector A,Vector B)
{
//计算AB夹角
return acos(Dot(A,B)/Length(A)/Length(B));
}
double Area2(Point A,Point B,Point C)
{
//计算三角形ABC的面积的二倍
return fabs(Cross(B-A,C-A));
}
Vector Rotate(Vector a,double rad)
{
//向量逆时针旋转rad角
//rad弧度
return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
Vector Normal(Vector a)
{
//计算向量的单位法线,即左转90度,长度归一化。
//用前确保A不是零向量
double l=Length(a);
return Vector(-a.y/l,a.x/l);
}
double DistanceToLine(Point p,Point a,Point b)
{
//计算点P到直线AB距离
Point v1=b-a;
Point v2=p-a;
return fabs(Cross(v1,v2))/Length(v1);
//如果不取绝对值,得的是有向距离
}
Point GetLineProjection(Point p,Point a,Point b)
{
//求点在直线上投影
//AB直线:A+tv , 投影Q的参数为 t0
//由 Dot(v,P-(A+t0*v))==0 得出
Vector v=b-a;
return a+v*(Dot(v,p-a)/Dot(v,v));
}
//-------------------------------------------------
int ConvexHull(Point* p,int n,Point* ch)
{
//计算凸包,输入点数组p,个数为n,输出点数组ch,函数返回凸包顶点数
//输入不能有重复点,函数执行完后输入点的顺序被破坏
//如果不希望在凸包的边上有输入点,把两个<=改成<
//在精度要求高时建议用dcmp比较
sort(p,p+n);
int m=0;
for(int i=0;i<n;i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-2;i>=0;i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
m--;
ch[m++]=p[i];
}
if(n>1)
m--;
return m;
}
bool OnSegment(Point p,Point a1,Point a2)
{
//判断一个点在线段上
return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
bool right(Point p,Point a,Point b)
{
return dcmp(cos(Angle(b-a,p-b))) > 0;
}
bool left(Point p,Point a,Point b)
{
return dcmp(cos(Angle(p-a,a-b))) > 0;
}
int n;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
while(~scanf("%d",&n))
{
rep(i,n) a[i].in();
int cnt = ConvexHull(a,n,p);
n = cnt;
double ans = INF;
p[n] = p[0];
int j = 1,k = 1, l = 0;
double tmp = 0;
for(int o=n-1;;o=(o-1+n)%n) //求左边的起始位置
{
Vector Nor0 = Normal(p[1] - p[0]);
double dis = DistanceToLine(p[o],p[0],p[0]+Nor0);
if(!left(p[o],p[0],p[1]))dis = -dis;
if(dcmp(dis - tmp) <= 0) {l=(o+1)%n;break;}
}
rep(i,n)
{
Vector Nor = Normal(p[i+1] - p[i]);
double dis = 0, dis1 = 0,dis2 = 0;
double t,tt;
while(1) //右边最远点
{
t = DistanceToLine(p[(j+1)%n],p[i+1],p[i+1]+Nor);
tt = DistanceToLine(p[j],p[i+1],p[i+1]+Nor);
if(!right(p[(j+1)%n],p[i],p[i+1])) t = -t;
if(!right(p[j],p[i],p[i+1])) tt = -tt;
if(dcmp(t - tt) < 0) break;
j = (j+1)%n;
}
tt = DistanceToLine(p[j],p[i+1],p[i+1]+Nor);
if(!right(p[j],p[i],p[i+1])) tt = -tt;
dis1 = max(dis1,tt);
while(1) //上方最远点
{
t = DistanceToLine(p[(k+1)%n],p[i],p[i+1]);
tt = DistanceToLine(p[k],p[i],p[i+1]);
if(dcmp(t - tt) < 0) break;
k = (k+1)%n;
}
dis = max(dis, DistanceToLine(p[k],p[i],p[i+1]));
while(1) //左边最远点
{
t = DistanceToLine(p[(l+1)%n],p[i],p[i]+Nor);
tt = DistanceToLine(p[l],p[i],p[i]+Nor);
if(!left(p[(l+1)%n],p[i],p[i+1])) t = -t;
if(!left(p[l],p[i],p[i+1])) tt = -tt;
if(dcmp(t - tt) < 0) break;
l = (l+1)%n;
}
tt = DistanceToLine(p[l],p[i],p[i]+Nor);
if(!left(p[l],p[i],p[i+1])) tt = -tt;
dis2 = max(dis2,tt);
ans = min(ans,2*(dis+dis1+dis2+Length(p[i+1]-p[i])));
}
printf("%.6lf\n",ans);
}
return 0;
}