zoukankan      html  css  js  c++  java
  • 巡逻路线

    题目

    给到(N) ((N{le}50))个点,求两个不相交的凸包,使得其中面积较大的那个面积最小。

    分析

    比赛的时候还剩一个半小时写这个题,其实就是很简单的计算几何,但是因为一些原因想复杂了。这里还学到了向量叉积。
    因为(N)很小,所以可以直接枚举两个点,作出一条直线,把点分到两边,直接计算即可。问题在于,这条直线上的点该放到哪边。场上分类讨论了一下,分组就写了近70行,其实不用这么麻烦。只要线上的点都放在同一边,所有情况都会枚举到。
    现在问题是如何判断一个定点在一条给定直线的哪一边。使用向量叉积:

    [{oldsymbol a}=(x\_a,y\_a), oldsymbol b=(x\_b,y\_b) \ oldsymbol a imes oldsymbol b=|oldsymbol a|*|oldsymbol b|*sin(oldsymbol a,oldsymbol b)=x \_ a * y \_ b-x \_ b * y \_a ]

    向量公式与坐标公式可用(sin)的差角公式得到。
    因此,若有两个向量({oldsymbol a})(oldsymbol b),那么令(oldsymbol c=oldsymbol a imes oldsymbol b),若(oldsymbol c=0),则(oldsymbol a)(oldsymbol b)在同一方向上。若(oldsymbol c<0),则(oldsymbol b)(oldsymbol a)的顺时针方向上,(oldsymbol b)(oldsymbol a)的逆时针方向上。同时,由:

    [S\_{ riangle ABC}={frac {1}{2}} a * b * sinC ]

    可得:

    [|{oldsymbol a} { imes} {oldsymbol b}|=2*S_{ riangle OAB} ]

    可用向量叉积进行极角排序(以一个点建立极坐标按照顺时针或者逆时针编号)和计算三角形面积。

    代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long double longd;
    const int maxn=55;
    const longd eps=1e-9;
    struct node {
    	longd x,y;
    	bool operator == (const node a) const {
    		return x==a.x && y==a.y;	
    	}
    } a[maxn],lf[maxn],rt[maxn];
    int ls,rs,ts,n;
    inline bool byall(node a,node b) {
    	return a.x==b.x?a.y<b.y:a.x<b.x;
    }
    inline longd sqr(longd x) {
    	return x*x;
    }
    inline longd dis(node a,node b) {
    	return sqrt(sqr(b.x-a.x)+sqr(b.y-a.y));
    }
    inline longd cross(node a,node b,node c) {
    	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
    }
    inline void where(int thea,int theb) {
    	node pa=a[thea],pb=a[theb];
    	for (int i=1;i<=n;++i) if (cross(pa,pb,a[i])>=0) lf[++ls]=a[i]; else rt[++rs]=a[i];		
    }
    node sta[maxn];
    node the;
    inline bool angle(node a,node b) {
    	longd ji=cross(the,a,b);
    	if (ji==0) return dis(the,a)<dis(the,b); 
    	return ji<0;
    }
    inline void pack(node t[],int &lt) {
    	int gs=0,top;
    	if (lt<2) return;
    	the.y=the.x=1e300;
    	int id=0;
    	for (int i=1;i<=lt;++i) if (t[i].x<the.x || (t[i].x==the.x && t[i].y<the.y)) the=t[i],id=i;
    	swap(t[1],t[id]);
    	sort(t+2,t+lt+1,angle);
    	top=0;
    	for (int i=1;i<=lt;++i) {
    		while (top>1 && cross(sta[top-1],sta[top],t[i])>=0) --top;
    		sta[++top]=t[i];
    	}
    	lt=top;
    	for (int i=1;i<=lt;++i) t[i]=sta[i];
    }
    inline longd size(node t[],int lt) {
    	longd ret=0;
    	node da=t[1];
    	for (int i=2;i<lt;++i) ret+=cross(t[1],t[i+1],t[i])/2;
    	return ret;
    }
    int main() {
    	#ifndef ONLINE_JUDGE
    		freopen("test.in","r",stdin);
    	#endif
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i) scanf("%Lf%Lf",&a[i].x,&a[i].y);
    	sort(a+1,a+n+1,byall);
    	n=unique(a+1,a+n+1)-a-1;
    	if (n<=4) printf("%.6Lf
    ",(longd)0.0),exit(0);
    	longd ans=1e300,sa,sb;
    	for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) {
    		ls=0,rs=0;
    		memset(lf,0,sizeof lf),memset(rt,0,sizeof rt);
    		where(i,j);
    		pack(lf,ls);
    		pack(rt,rs);
    		sa=size(lf,ls);
    		sb=size(rt,rs);
    		ans=min(ans,max(sa,sb));
    	}
    	printf("%.6Lf
    ",ans);
    }
    
  • 相关阅读:
    堆排序
    伽马分布
    隔壁-贪心
    对刚—约瑟夫环
    站军姿-两圆并集
    单纯的线性筛素数
    3兔子
    2.圆桌游戏
    1.花
    历史
  • 原文地址:https://www.cnblogs.com/owenyu/p/6724747.html
Copyright © 2011-2022 走看看