凸包问题




#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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值