HDU 1558 判断两个线段相交附带并查集

本文介绍了一种算法,该算法通过判断线段是否相交来确定线段集合,并实现了查询特定线段所在集合大小的功能。使用了并查集进行集合管理,以及通过向量叉积判断线段相交。

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

         题目的大概意思是只要两个线段连在一起就可以算在一个集合里面,问第k条直线处在的集合中有多少条直线。

        假设在已知判断线段相交的方法的情况下,把一条新的直线放到平面上的时候,我们把这条直线和之前的所有直线判定一遍,假若相交,则合并这两个集合,因为n<=1000,顶多也只有1000条直线,时间还是可以承受的。。况且假若不一一比较的话,也没什么简单的办法来获得我们需要的信息。。。

        接下来就是解决判定线段相交的问题了,借用了算法导论上的办法,以下是代码:


#include<cstdio>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<double,double> point;

struct line{
    point p1,p2;
    line(double a=0,double b=0,double c=0,double d=0):p1(make_pair(a,b)),p2(make_pair(c,d)){};
}te,arr[1010];

int t,n,qu,cou=1,sets[1010],sz[1010];
char c;

int _find(int x){return (x==sets[x])?x:sets[x]=_find(sets[x]);}
bool _merge(int x,int y),judge(const line&,const line&),on_segment(const point&,const point&,const point&);
double direction(const point&,const point&,const point&);

int main(){
    scanf("%d",&t);
    for(int times=1;times<=t;++times){
        scanf("%d%*c",&n);
        while(n--){
            scanf("%c",&c);
            if(c=='Q'){
                scanf("%d%*c",&qu);
                printf("%d\n",sz[_find(qu)]);
            }
            else{
                sets[cou]=cou,sz[cou]=1;
                scanf("%lf%lf%lf%lf%*c",&te.p1.first,&te.p1.second,&te.p2.first,&te.p2.second);
               // printf("%lf %lf %lf %lf\n",te.p1.first,te.p1.second,te.p2.first,te.p2.second);
                arr[cou]=te;
                for(int i=1;i<cou;++i){
                    if(judge(arr[i],te))
                        _merge(i,cou);//printf("%s\n",(_merge(i,cou)?"success":"failed"));
                }
                ++cou;
            }
        }
        cou=1;
        if(times!=t)
         printf("\n");
    }
    return 0;
}

bool _merge(int x,int y){
    int a=_find(x),b=_find(y);
    if(a!=b)
        sz[a]+=sz[b],sets[b]=a;
    return a!=b;
}

bool judge(const line&a,const line& b){
    double d1=direction(b.p1,b.p2,a.p1),d2=direction(b.p1,b.p2,a.p2),d3=direction(a.p1,a.p2,b.p1),d4=direction(a.p1,a.p2,b.p2);
   // printf("%lf %lf %lf %lf\n",d1,d2,d3,d4);
    if(((d1>1E-5&&d2<-1E-5)||(d1<-1E-5&&d2>1E-5))&&((d3>1E-5&&d4<-1E-5)||(d3<-1E-5&&d4>1E-5)))
        return true;
    else if(fabs(d1)<1E-5&&on_segment(b.p1,b.p2,a.p1))
        return true;
    else if(fabs(d2)<1E-5&&on_segment(b.p1,b.p2,a.p2))
        return true;
    else if(fabs(d3)<1E-5&&on_segment(a.p1,a.p2,b.p1))
        return true;
    else if(fabs(d4)<1E-5&&on_segment(a.p1,a.p2,b.p2))
        return true;
    else
        return false;
}

double direction(const point&a,const point&b,const point& c){
    return (c.first-a.first)*(b.second-a.second)-(b.first-a.first)*(c.second-a.second);
}

bool on_segment(const point&a,const point&b,const point& c){
    return  min(a.first,b.first)<=c.first&&c.first<=max(a.first,b.first)&&min(a.second,b.second)<=c.second&&c.second<=max(a.second,b.second);
}

       函数说明:_find函数是查找元素同时自带路径压缩的写法

                        _merge函数用于合并两个集合,其实在这里返回值完全可以不要,只是我利用返回值找出了编写时的一个小bug。

                       judge函数用于判断两个线段是否相交,我为了迎合算法导论上的写法,所以参数是那么写的,,当然了,要直接拿去用也可以。

                       direction函数和on_segment函数也解释一下吧,direction函数用于返回两个向量的叉积,具体的算法导论上面有,大概意思就是判断方向,要求两条向量各在两侧

                       on_segment函数用于处理一条线段的端点恰好处于另一条线段上的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值