hdu1558线段相交与并查集

小吐嘈:第一次写这种计算几何的东西,被坑的莫明奇妙,最后才发现,不是自己的函数写错了,而是在读入的时候用llf去读数据,然后就WA的莫明奇妙。double 用%lf,long double 才是%llf呀,实在是不用不知道,一用就吓一跳。然后,输入的时候,又是那个格式呀,真的是什么鬼。然后,对于double 型的变量,在比较的时候都是不精确比较,必须要指定一个精度才可以。可两个double的差小于这个精度的时候,我们就可以认为他们相等了(想想微积分的hdu1558线段相交与并查集_第1张图片语言吧)
言归正传,先看题意:

hdu1558线段相交与并查集_第2张图片
给你一系列线段,如果两个线段相交就将它们归为一类,要求某个线段所在的类有多少根线段。
既然有集合的相并那么就毫不犹豫的使用并查集啦。
然而,这里的重点其实是就是判断线段相交。
如何判断线段相交呢?
相交又分为普通相交和有端点在另一个线段上。
首先复习下线性代数叉积的知识。
hdu1558线段相交与并查集_第3张图片
这里写图片描述>0时,向量P在向量Q在顺时针。这里写图片描述<0向量P在向量Q在逆时针。
hdu1558线段相交与并查集_第4张图片
对于AB与CD相交的一般情况(中间那个情况)
我们可以发现向量CA与向量CB在向量CD的两侧,同时,向量CA和向量DA也要在AB在两侧(这两个两侧要同时满足才行,不然,又如右边那个反例,只满足CA CB 在CD的两侧,但是不满足CA,DA在AB在两侧)。
而对于其中有一个线段上的一个端点在另一条线段的线段的情况(比如左图),发现AC叉乘BC为0,因此可以这么判断是否有点共线。
以下是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <limits.h>
#include <queue>
#include <stack>
#include <vector>
#define N 1010
using namespace std;
struct Set
{
    int fa ;
    int sub;
}set[N];
#define exp 1e-10//精度
struct Node
{
    double x ,y;
};
struct line 
{
    Node A,B;
}l[N];
int judge(Node A,Node B,Node C, Node D)
{
        double f1 = (A.y-C.y)*(A.x-B.x)-(A.x-C.x)*(A.y-B.y);//AC X AB
        double f2 = (A.y-D.y)*(A.x-B.x)-(A.x-D.x)*(A.y-B.y);//AD X AB
        double f3 = (C.y-A.y)*(C.x-D.x)-(C.x-A.x)*(C.y-D.y);//CA X CD
        double f4 = (C.x-D.x)*(C.y-B.y)-(C.x-B.x)*(C.y-D.y);//CB X CD
        if(f1*f2<=exp && f3*f4<=exp) return 1;
    return 0 ;
}
int find(int x )
{
    int i, j , k ;
    i = x ;
    int sum = 0 ;
    while(set[i].fa!=i)
    {
        i = set[i].fa;
    }
    j = x ;
    return i ;
}
void join(int x ,int y )
{
    int fx = find(x);
    int fy = find(y);
    if(fx!=fy)
    {
        set[fx].fa=fy;
        set[fy].sub+=set[fx].sub;
    }
}
int main()
{
    int t ; 
    scanf("%d",&t);
    while(t--)
    {
        int n ;
        scanf("%d",&n);
        for(int i = 0 ;i<=n;i++)
        {
                set[i].fa = i ;
                set[i].sub=1;
        }
        int cnt = 1 ;
        while(n--)
        {
            char ch;
            scanf(" %c",&ch);
            if(ch=='P')
            {
                scanf("%lf%lf%lf%lf",&(l[cnt].A.x),&(l[cnt].A.y),&(l[cnt].B.x),&(l[cnt].B.y));
                //printf("A(%0.4lf,%.4lf) B(%.4lf,%.4lf)\n",l[cnt].A.x,l[cnt].A.y,l[cnt].B.x,l[cnt].B.y);//注意double使用lf读,float使用f(float 最好不用,精度太低)
                for(int i =  1 ; i < cnt;i++)
                {
                    if(judge(l[cnt].A,l[cnt].B,l[i].A,l[i].B)==1)
                    {
                        join(i,cnt);
                    }
                }
                cnt++;
            }
            else
            {
                int q ;
                scanf("%d",&q);
                printf("%d\n",set[find(q)].sub);
            }
        }
        if(t) printf("\n");//注意输出格式呀
    }
    return 0 ;
}

你可能感兴趣的:(double,格式,并查集,线段相交,计算几何)