[poj 1127]Jack Straws[线段相交][并查集]

题意:

给出一系列线段,判断某两个线段是否连通.

思路:

根据线段相交情况建立并查集, 在同一并查集中则连通.

(第一反应是强连通分量...实际上只要判断共存即可, 具体的方向啊是没有关系的..)


并查集合并的时候是根节点合并.

快速排斥试验不是必需的, 大规模数据可能是个优化吧.

跨立试验注意共线的情况.

共线判断注意与y 轴平行的情况.

 

#include <cstdio>

#include <cstring>

#include <cmath>

using namespace std;

const double EPS = 1e-6;

const int INF = 0x3f3f3f3f;

const int MAXN = 15;

typedef struct node

{

    double x,y;

}point;

point a[MAXN],b[MAXN];

bool adj[MAXN][MAXN];

int n;



int max(int a, int b)

{

    int diff = b - a;

    return b - (diff & (diff>>31));

}

int min(int a, int b)

{

    int diff = b - a;

    return a + (diff & (diff>>31));

}

int fa[MAXN];



int FindSet(int x)

{

    if(x==fa[x])    return fa[x];

    return fa[x] = FindSet(fa[x]);

}



int dcmp(double p)

{

    if(fabs(p)<EPS)  return 0;

    return p>0?1:-1;

}



double det(double x1, double y1, double x2, double y2)

{

    return x1*y2 - x2*y1;

}



double cross(point A, point B, point P)

{

    return det(B.x - A.x, B.y - A.y, P.x - A.x, P.y - A.y);

}



bool ck(point A, point B, point C, point D)

{

    int min1x = min(A.x,B.x), min2x = min(C.x,D.x);

    int max1x = max(A.x,B.x), max2x = max(C.x,D.x);

    int min1y = min(A.y,B.y), min2y = min(C.y,D.y);

    int max1y = max(A.y,B.y), max2y = max(C.y,D.y);

    /*if(max(max1x,max2x)-min(min1x,min2x)>(max1x-min1x)+(max2x+min2x) ||

       max(max1y,max2y)-min(min1y,min2y)>(max1y-min1y)+(max2y+min2y))   return false;*/

    int a = dcmp(cross(A, B, C));

    int b = dcmp(cross(A, B, D));

    if(!a && !b)

        return (   max(max1x,max2x)-min(min1x,min2x)<=(max1x-min1x)+(max2x-min2x)

                && max(max1y,max2y)-min(min1y,min2y)<=(max1y-min1y)+(max2y-min2y)  );

    int c = dcmp(cross(C, D, A));

    int d = dcmp(cross(C, D, B));

    return (( a* b <= 0) && ( c* d <= 0));//规范或不规范相交

}



void BuildSet()

{

    for(int i=1;i<=n;i++)

    {

        fa[i] = i;

    }

    for(int i=1;i<=n;i++)

    {

        for(int j=i+1;j<=n;j++)

        {

            if(ck(a[i],b[i],a[j],b[j]))

            {

                int fi = FindSet(i), fj = FindSet(j);//并查集写错了= =

                fa[fi] = fj;

            }

        }

    }

}



bool check(int a, int b)

{

    return (FindSet(a)==FindSet(b));

}



int main()

{

    int x, y;

    while(scanf("%d",&n)==1 && n)

    {

        for(int i=1;i<=n;i++)

            scanf("%lf %lf %lf %lf",&a[i].x,&a[i].y,&b[i].x,&b[i].y);

        BuildSet();

        while(scanf("%d %d",&x,&y)==2 && (x+y))

        {

            if(check(x, y)) printf("CONNECTED\n");

            else    printf("NOT CONNECTED\n");

        }

    }



}


 

 

你可能感兴趣的:(poj)