携程决赛第二题

飞机的碎片

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值