HDU 1558 Segment set(并查集)

题意:给你一些线段的起点和终点的坐标,最后问和某个线段相连的或者间接相连的线段有多少个(包括本身)?

P X1 Y1X2 Y2  起点(X1,X2)终点(X2,Y2);按照出现次数依次编号为1,2,3,4......

Q N  问和第N个线段相交或者间接相交的线段有多少个,所谓间接相交就是如果 1 和 2相交  , 2 和  3相交  那么  1 和 3 就是间接相交。。。。。

解题思路:每给出一个线段就和之前的所有线段判断是否相交,如果相交就合并,最后利用路径压缩后所有节点的父节点都是根节点的特征,找出与所问的这条线段相交的数量(包括本身)。记得最后那个换行在每个样列之间。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#define        EPS .1e-6
using namespace std;
const int MAXN = 1e3 + 3;
int pre[MAXN];

struct TPoint   //代表一个点
{
    float x,y; //横纵坐标
};

struct TLineSeg   //一条线段
{
    TPoint a,b;   //起点和终点
};

float multiply(TPoint p1,TPoint p2,TPoint p0)
{
    return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}

int intersect(TLineSeg u,TLineSeg v) //判断两条是否相交
{
    return( (max(u.a.x,u.b.x) >= min(v.a.x,v.b.x))&&(max(v.a.x,v.b.x) >= min(u.a.x,u.b.x))&& (max(u.a.y,u.b.y)>= min(v.a.y,v.b.y))&&  (max(v.a.y,v.b.y)>= min(u.a.y,u.b.y))&& (multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)>=0)&&(multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)>=0));

}

int Find(int x)
{
    int r = x;
    while(pre[r] != r)
    {
        r = pre[r];
    }
    int i = x,j;
    while(pre[i] != r)
    {
        j = i;
        i = pre[i];
        pre[j] = r;
    }
    return r;
}

void Mix(int a,int b)
{
    int x = Find(a);
    int y = Find(b);
    if(x > y)
    {
        pre[x] = y;
    }
    if(x < y)
    {
        pre[y] = x;
    }
}


void Mst()
{
    for(int i = 1; i <= MAXN; i++)
    {
        pre[i] = i;
    }
}
int main()
{
    int T;
    //freopen("in.txt","r",stdin);
   // freopen("out.txt","w",stdout);
    scanf("%d", &T);
    while(T--)
    {
        Mst();
        int N;
        scanf("%d", &N);
        struct TLineSeg S[MAXN];
        memset(S,0,sizeof(S));
        int len = 1;
        while(N--)
        {
            char s[3] = {0};
            scanf("%s",s);
            if(s[0] == 'P')
            {
                scanf("%f%f%f%f",&S[len].a.x,&S[len].a.y,&S[len].b.x,&S[len].b.y);
                if(len >= 2)    
                {
                    for(int i = 1; i <len; i++) 
                    {
                        if(intersect(S[len],S[i]))      //如果相交就合并
                        {
                            Mix(i,len);
                        }
                    }
                }
                len++;
            }
            if(s[0] == 'Q')
            {
                int num;
                scanf("%d",&num);
                for(int i = 1;i <= len; i++)
                    Find(i);
                int ans = 0;
                for(int i = 1; i <= len ;i++)    //统计和这条线段相连的有多少个(包括本身)
                    if(pre[i] == pre[num])
                        ans++;
                printf("%d\n",ans);
            }
        }
        if(T)     //记得最后有一个换行,记得最后有一个换行,记得最后有一个换行!!!!!!
            cout <<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值