HDU 1558 (并查集+判断线段相交)

本文介绍了一个使用并查集解决边相交问题的算法实现案例。通过定义点和边的数据结构,并利用模板来判断两条边是否相交,进而进行并查集的合并操作。文中详细解释了如何通过并查集来确定相连边的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: 输入每一条边,如果两个边相交则同为一个集合,问题是求某一条边所在集合的边的数目。
很明显的并查集,但是怎么判断边与边的相交呢?这里用到了模板。

知道了边相交,那么find 和 merge 便不难了。

注意:
1. 用num存储集合边的数目
2. 类的简单使用,edge存储边的起始点
3. Find里面用到了优化


#include<cstdio>
#include<cmath>
#include<iostream>

#define Max 1010

using namespace std;

class point
{
    public:
    double x,y;
};

class edge
{
    public:
    point a,b;
}e[Max];

int root[Max];
int num[Max];

//-----------------------------------------------------------------------------------

double xmult(point a,point b,point c)
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool OnSegment(point a,point b,point c)
{
    return c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x)&&c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y);
}

bool Cross(point a,point b,point c,point d)     //判断是否相交
{
    double d1,d2,d3,d4;
    d1=xmult(c,d,a);
    d2=xmult(c,d,b);
    d3=xmult(a,b,c);
    d4=xmult(a,b,d);
    if(d1*d2<0&&d3*d4<0)  return 1;
    else    if(d1==0&&OnSegment(c,d,a)) return 1;
    else    if(d2==0&&OnSegment(c,d,b)) return 1;
    else    if(d3==0&&OnSegment(a,b,c)) return 1;
    else    if(d4==0&&OnSegment(a,b,d)) return 1;
    return 0;
}

//----------------------------------------------------------------------------------

int Find(int x)
{
    int _x = x;
    while(_x != root[_x])
        _x = root[_x];
    while(x != root[x]){
        int i = root[x];
        root[x] = _x;
        x = i;
    }
    return _x;
}

void Merge(int u,int v)
{
    int _u = Find(u);
    int _v = Find(v);
    if(_u != _v){
        root[_u] = _v;
        num[_v] += num[_u];
    }
}

int main()
{
   // freopen("in.txt","r",stdin);
    int ncase;
    scanf("%d",&ncase);
    while(ncase--){

        int n;
        scanf("%d",&n);

        for(int i = 1;i <= n; i++){
            root[i] = i;
            num[i] = true;
        }
        int edgenum = 0;
        getchar();
        for(int i = 1;i <= n; i++){
            char c;
            scanf("%c",&c);
            if(c == 'P'){
                edgenum++;
                scanf("%lf%lf%lf%lf",&e[edgenum].a.x,&e[edgenum].a.y,&e[edgenum].b.x,&e[edgenum].b.y);
                for(int j = 1;j < edgenum; j++){
                    if(Find(j) != Find(edgenum)) {
                        if(Cross(e[j].a,e[j].b,e[edgenum].a,e[edgenum].b))
                            Merge(j,edgenum);
                    }
                }
            }
            else if(c == 'Q') {
                int ans;
                scanf("%d",&ans);
                printf("%d\n",num[Find(ans)]);
            }
            getchar();
        }
        if(ncase)
            printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值