FZU 2153 A simple geometric problems 凸包 + DP

给出五十个点,构造出一个凸包,让尽可能多的点在上面。


首先要说一下凸包的构造过程。

极角:设参考点为R,对于点P的极角即为向量RP与X正方向的夹角。

显然极角的取值范围为 [0,180] ,所以参考点R应选择 y 坐标最小的,若有多个,则选x最小的。

然后按极角大小升序排列。参考点不参与排序,或者说默认为最小。

设置空栈。

从前向后枚举点 p[i]。

当栈中的元素个数小于 2 时,直接将p[i] 放入栈内。

当栈中元素个数大于等于 2 时。

         设栈顶的两个元素为 pa , pb(pb为后入栈的那个)。

        若向量papb[i] 叉乘 向量papb 小于 0,则将 p[i] 入栈,i++。否则将pb弹出,i 不变,继续计算当前点。

以上即是就是葛立恒算法的整个流程。

其实明白了上面流程就可以发现,只要确定了参考点和末尾的两个点就可知一个新点是否可以加入此凸包。

所以只需要枚举 参考点,两个末尾点 和 等待加入的点。时间复杂度o[n^4]。稍微剪剪指就可以了。

枚举参考点时应注意 对于参考点R,P.y < R.y || (P.y == R.y && P.x< R.x) ,则p不参与计算,这是因为极角的计算问题。


PS :思路是学姐点拨的,本菜充其量也就算个码农。。。


http://blog.csdn.net/zmx354/article/details/23004375


#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long int
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 1000000007
#define LM(a,b) (((ULL)(a))<<(b))
#define RM(a,b) (((ULL)(a))>>(b))

using namespace std;

const double PI = acos(-1.0);

struct P
{
    double x,y,a;
}p[1100],tp[1100];

int dp[51][51];

bool cmpxy(P p1,P p2)
{
    return ( p1.y < p2.y || (fabs(p1.y-p2.y) < EPS && p1.x < p1.x ) );
}

bool cmp_angle(P p1,P p2)
{
    return (p1.a < p2.a || (fabs(p1.a-p2.a) < EPS && p1.y < p2.y) ||(fabs(p1.a-p2.a) < EPS && fabs(p1.y-p2.y) < EPS && p1.x < p2.x)   );
}

double X_Mul(P a1,P a2,P b1,P b2)
{
    P v1 = {a2.x-a1.x,a2.y-a1.y},v2 = {b2.x-b1.x,b2.y-b1.y};
    return v1.x*v2.y - v1.y*v2.x;
}

double Cal_Angle(P t,P p)
{
    return ((t.x-p.x)*(t.x-p.x) + 1 - (t.x-p.x-1)*(t.x-p.x-1))/(2*sqrt((t.x-p.x)*(t.x-p.x) + (t.y-p.y)*(t.y-p.y)));
}

void Sort_By_Angle(P *p,int n)
{
    P re = p[0];

    p[0].a = -2;

    for(int i = 1;i < n; ++i)
    {
        p[i].a = Cal_Angle(re,p[i]);
    }

    sort(p,p+n,cmp_angle);
}

int Max;

void Updata_Max(P *p,int n)
{
    int i,j,k;

    for(i = 0;i < n; ++i)
    {
        tp[i] = p[i];
    }

    Sort_By_Angle(tp,n);

    for(i = 1;i < n; ++i)
    {
        for(j = i+1;j < n; ++j)
            dp[i][j] = 3;
    }

    for(i = 1;i < n; ++i)
    {
        for(j = i+1;j < n; ++j)
        {
           
            for(k = j+1;k < n; ++k)
            {
                if(dp[i][j] >= dp[j][k] &&  X_Mul(tp[i],tp[j],tp[i],tp[k]) > 0)
                {
                    dp[j][k] = dp[i][j]+1;

                    Max = max(dp[j][k],Max);
                }
            }
           
        }
    }
}

int main()
{
    int icase = 1,T,n,i;

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d",&n);

        for(i = 0;i < n; ++i)
        {
            scanf("%lf %lf",&p[i].x,&p[i].y);
        }

        sort(p,p+n,cmpxy);

        Max = 3;

        for(i = 0;i < n ; ++i)
        {
            if(n-i <= Max)
                break;
            Updata_Max(&p[i],n-i);
        }
        
        printf("Case#%d: %d\n",icase++,Max);
    }
    return 0;
}








你可能感兴趣的:(FZU 2153 A simple geometric problems 凸包 + DP)