现在的位置: 首页 > 综合 > 正文

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

2017年12月16日 ⁄ 综合 ⁄ 共 1843字 ⁄ 字号 评论关闭

题意:

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

思路:

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

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

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

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

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

共线判断注意与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");
        }
    }

}

抱歉!评论已关闭.