A Classic Myth: Flatland Superhero

http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11264&courseid=107

题意:在二维平面内给若干点,现在在用一个平行四边形把所有的点都围住,求满足这个条件的最小平行四边形面积。
思路:
把凸包弄出来后,直接枚举凸包上的两条边,作为平行四边形的相邻边,再求出到这两边最远的两个点,来生成另外两条边。
然后知道四条边,可以求出四个顶点,再求面积就好了。
View Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
struct point{
    double x,y;
    void scan(){scanf("%lf %lf",&x,&y);}
    friend bool operator < (const point &l,const point &r){
        return l.y < r.y || (l.y==r.y&&l.x<r.x);
    }
}as[1005],bs[1005];
int dis[1005];
double xmult(double x1,double y1,double x2,double y2,double x0,double y0){
    return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
}
double distance(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
//点到直线的距离
double disptoline(double x,double y,double x1,double y1,double x2,double y2){
    return fabs(xmult(x,y,x1,y1,x2,y2))/distance(x1,y1,x2,y2);
}
bool mult(point sp,point ep,point op){
    return (sp.x - op.x) * (ep.y - op.y) >= (ep.x - op.x) * (sp.y - op.y);
}
//求凸包
int graham(point pnt[],int n,point res[])
{
    int i,len,k=0,top=1;
    sort(pnt,pnt+n);
    if(n==0)return 0; res[0]=pnt[0];
    if(n==1)return 1; res[1]=pnt[1];
    if(n==2)return 2; res[2]=pnt[2];
    for(i = 2; i < n; ++ i){
        while(top && mult(pnt[i],res[top],res[top-1]))top--;
        res[++top]=pnt[i];
    }
    len = top; res[++top]=pnt[n-2];
    for(i=n-3;i>=0;--i){
        while(top!=len&&mult(pnt[i],res[top],res[top-1]))top--;
        res[++top]=pnt[i];
    }
    return top;
}
//判断两直线是否平行
bool px(point a,point b,point c,point d){
    return (a.y-b.y)*(c.x-d.x)==(c.y-d.y)*(a.x-b.x);
}
//知直线ab,求直线cd,使得cd平行ab
point getpoint(point c,point b,point a)
{
    point d;
    if(a.x==b.x){
       d.x = c.x;
       d.y = c.y + 1;
       return d;
    }
    d.x=c.x+1;
    d.y=(a.y-b.y)/(a.x-b.x)+c.y;
    return d;
}
//不直线与直线的交点
point intersection(point u1,point u2,point v1,point v2)
{
    point ret = u1;
    double t = ((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
    ret.x+=(u2.x-u1.x)*t;
    ret.y+=(u2.y-u1.y)*t;
    return ret;
}
int main()
{
    int i,j,k,t,n,cas=0;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(i=0;i<n;++i)bs[i].scan();
        n = graham(bs,n,as);
        as[n]=as[0];
        for(i = 0; i < n; ++ i){
            double mx=0,tmp;
            int idx;
            for(j=0;j<n;++j){
                tmp=disptoline(as[j].x,as[j].y,as[i].x,as[i].y,as[i+1].x,as[i+1].y);
                if(tmp>mx)mx=tmp,idx=j;
            }
            dis[i]=idx;
        }
        double mx = 1e9;
        for(i=0;i<n;++i){
            for(j=0;j<n;++j){
                if(i==j||px(as[i],as[i+1],as[j],as[j+1]))continue;
                point a = getpoint(as[dis[i]],as[i],as[i+1]);
                point b = getpoint(as[dis[j]],as[j],as[j+1]);
                //bs[0]~bs[3]为平行四边形的四个顶点
                bs[0] = intersection(as[i],as[i+1],as[j],as[j+1]);
                bs[1] = intersection(as[i],as[i+1],as[dis[j]],b);
                bs[2] = intersection(as[j],as[j+1],as[dis[i]],a);
                bs[3] = intersection(a,as[dis[i]],b,as[dis[j]]);
                double tmp=fabs((bs[0].x-bs[1].x)*(bs[2].y-bs[1].y)-(bs[2].x-bs[1].x)*(bs[0].y-bs[1].y));
                if(tmp<mx)mx=tmp;
            }
        }
        printf("Swarm %d Parallelogram Area: %.4lf\n",++cas,mx);
    }
    return 0;
}

 

posted on 2012-10-04 20:02  aigoruan  阅读(200)  评论(0)    收藏  举报

导航