hdu 1558 Segment set 线段相交+并查集

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1558

题目大意:有T组测试数据,对每组测试数据,有N行,如果输入的字符为P ,接着输入两个点的横纵坐标,即为一个线段的两个端点,如果字符为P,接着输入一个序号K,输出与第K次输入的线段有交点的线段的总数。题意很明显使用并查集,但是对于线段相交的判断比较麻烦,代码如下:

#include<stdio.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
int T,n;
struct point{double x,y;};//点的结构体
struct zb{point a,b;}s[1005];//线段的结构体
int f[1005],rank[1005];
void init()//并查集的初始化
{
    for(int i=1;i<1005;i++)
    {
        f[i]=i;rank[i]=1;
    }
}
int find(int x)//状态压缩查找
{
    if(x==f[x]) return x;
    return f[x]=find(f[x]);
}
void merge(int x,int y)//按秩合并
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        if(rank[fx]>rank[fy])
            {rank[fx]+=rank[fy];f[fy]=fx;}
        else
            {rank[fy]+=rank[fx];f[fx]=fy;}
    }
}
double ccw(point a,point b,point c)//三角形的有向面积,用来判断
//点c在直线a,b的左边还是右边,大于零左边,小于零右边,等于零直线上
{
    double m=(a.x*b.y+b.x*c.y+c.x*a.y-a.x*c.y-b.x*a.y-c.x*b.y);
    return m;
}
//判断两个线段是否相交,前面四个条件是使两条线段形成一个包围盒,如果有交点
//肯定在包围盒内,后面两个条件是保证使一条线段的两点不在另外一条线段的一侧
bool judge(point a,point b,point c,point d)
{
    if(max(a.x,b.x)>=min(c.x,d.x)&&max(a.y,b.y)>=min(c.y,d.y)&&
       max(c.x,d.x)>=min(a.x,b.x)&&max(c.y,d.y)>=min(a.y,b.y)&&
       ccw(a,b,c)*ccw(a,b,d)<=0&&ccw(c,d,a)*ccw(c,d,b)<=0)
        return true;
    return false;
}
int main()
{
    char c[2];
    scanf("%d",&T);
    while(T--)
    {
        int k=1;
        scanf("%d",&n);
        init();
        while(n--)
        {
            scanf("%s",c);
            if(c[0]=='P')
            {
                scanf("%lf%lf%lf%lf",&s[k].a.x,&s[k].a.y,&s[k].b.x,&s[k].b.y);
                for(int i=1;i<k;i++)
                {
                    if(judge(s[i].a,s[i].b,s[k].a,s[k].b))
                     merge(i,k);
                }
                k++;
            }
            else
            {
                int f;
                scanf("%d",&f);
                printf("%d\n",rank[find(f)]);//rank[]的大小就是当前包含的线段数
            }
        }
        if(T) printf("\n");
    }
}

这道题最重要的应该是学会了线段相交的模板。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值