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);
    }
    
  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/owenyu/p/6724747.html
Copyright © 2011-2022 走看看