凸包问题

来源:互联网 发布:nodejs于java跨域传值 编辑:程序博客网 时间:2024/05/16 10:13




#include<cstdio>#include<algorithm>#include<fstream>#include<cstring>#include<iostream>using namespace std;const int MAX=550;struct point{    int x;    int y;    int v;    int i;    int tmp;} Ini[MAX],res[MAX],p[MAX];bool flag[MAX];int ans[MAX];bool cmp(point A,point B)  //同速度的排序,仍然是找x小的和y小的;{    if(A.y==B.y)return A.x<B.x;    return A.y<B.y;}bool cmp1(point A,point B)//排序从大到小,以及同速度的x小点,同速度同x的y小点;这里是对原数组的排序;{    if(A.v>B.v)return true;    if(A.v==B.v)    {        if(A.x<B.x)return true;        if(A.x==B.x&&A.y<B.y)return true;    }    return false;}int cross(point A,point B,point C)//点积;{    return (B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y);}int Graham(point *p,int n){    //if (n<3)return n;    sort(p,p+n,cmp);    memset(flag,false,sizeof(flag));    int i;    int top=0;    for(i=0; i<n; i++)    {        while(top>=2&&cross(res[top-2],res[top-1],p[i])<0)/*构造下边界,若不在凸包上则将点出栈;(这里是判断如果点积小于0继续循环,知道找到凸包的点,而=0即共线情况也是凸包的点,也要跳出,所以这里不能取等)知道满足凸包条件跳出循环,然后记录;*/        {            top--;        }        res[top]=p[i];   //res数组存下在凸包上的点;        res[top].tmp=i; //记录入栈点的编号;
        top++;    }    for(i=0;i<top;i++)        flag[res[i].tmp]=true;     int t=top+1;    for(i=n-2; i>=0; i--) //i>=0    {        while(top>=t&&cross(res[top-2],res[top-1],p[i])<0)  //构造上边界;
            top--;        if(!flag[i]) res[top++]=p[i];  //满足条件且不在已构造的凸包内;        //if(i==0)top--;    }    /*for(i=0; i<top; i++)        printf("$%d %d\n",res[i].x,res[i].y);*/    return top;//返回凸包上点的个数;}int main(){    int n;    int i,j;    //ifstream cin("A.txt");    int __case=0;    while(cin>>n&&n)    {        for(i=0; i<n; i++)        {            cin>>Ini[i].x>>Ini[i].y>>Ini[i].v;            Ini[i].i=i;//标记位置id        }        sort(Ini,Ini+n,cmp1);//排序找出速度最大点(前面的好几位都是速度最大点),并按坐标排序;        //cout<<Ini[i-1].x<<Ini[i-1].y;        int tmp=0;        for(i=0; i<n; i++)        {            if(Ini[0].v>0&&Ini[0].v==Ini[i].v) tmp++;            else break;        }//筛出最大速度的点;        memset(ans,0,sizeof(ans));        point po;        for(i=0,j=0;i<tmp;i++)        {            po=Ini[i];            //flag=1;            if(i<tmp-1&&Ini[i+1].x==po.x&&Ini[i+1].y==po.y)//找重点 ,因为已经按排序过,所以重点一点是出现在相邻点之间;            {                while(i<tmp-1&&Ini[i+1].x==po.x&&Ini[i+1].y==po.y)                {                    ans[Ini[i].i]=-1;                    i++;                }                ans[Ini[i].i]=-1;   //重点则不可能无限,先标记掉;            }            p[j++]=po;//保留所有的符合的点,注意此时重点也要留下一个点。        }        int m=Graham(p,j);//传入数组时不仅要有地址,还要传入长度;此时传入的数组是已经去完重点的,在函数中就不用判断了;        printf("Case #%d: ",++__case);        for(i=0; i<m; i++)        {            if(!ans[res[i].i])ans[res[i].i]=1;//如果不是重点且在凸包上,则使其为1;        }        for(i=0; i<n; i++)        {            if(ans[i]==1)printf("1");            else printf("0");        }        printf("\n");    }    return 0;}

0 0
原创粉丝点击