POJ 1127 计算几何+并查集

Jack Straws
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 2945 Accepted: 1333

Description

In the game of Jack Straws, a number of plastic or wooden "straws" are dumped on the table and players try to remove them one-by-one without disturbing the other straws. Here, we are only concerned with if various pairs of straws are connected by a path of touching straws. You will be given a list of the endpoints for some straws (as if they were dumped on a large piece of graph paper) and then will be asked if various pairs of straws are connected. Note that touching is connecting, but also two straws can be connected indirectly via other connected straws.

Input

Input consist multiple case,each case consists of multiple lines. The first line will be an integer n (1 < n < 13) giving the number of straws on the table. Each of the next n lines contain 4 positive integers,x1,y1,x2 and y2, giving the coordinates, (x1,y1),(x2,y2) of the endpoints of a single straw. All coordinates will be less than 100. (Note that the straws will be of varying lengths.) The first straw entered will be known as straw #1, the second as straw #2, and so on. The remaining lines of the current case(except for the final line) will each contain two positive integers, a and b, both between 1 and n, inclusive. You are to determine if straw a can be connected to straw b. When a = 0 = b, the current case is terminated.

When n=0,the input is terminated.

There will be no illegal input and there are no zero-length straws.

Output

You should generate a line of output for each line containing a pair a and b, except the final line where a = 0 = b. The line should say simply "CONNECTED", if straw a is connected to straw b, or "NOT CONNECTED", if straw a is not connected to straw b. For our purposes, a straw is considered connected to itself.

Sample Input

7
1 6 3 3 
4 6 4 9 
4 5 6 7 
1 4 3 5 
3 5 5 5 
5 2 6 3 
5 4 7 2 
1 4 
1 6 
3 3 
6 7 
2 3 
1 3 
0 0

2
0 2 0 0
0 0 0 1
1 1
2 2
1 2
0 0

0

Sample Output

CONNECTED 
NOT CONNECTED 
CONNECTED 
CONNECTED 
NOT CONNECTED 
CONNECTED
CONNECTED
CONNECTED
CONNECTED


题意:给定N条线段的端点坐标,然后再给出若干个查询判断两线段是否相交。
思路:计算几何判断线段是否相交,并查集预处理好相交的线段,然后再度输出就好。
      这道题后面判断是否相交还有一种做法是日本人民提供的FLOYD算法可以遍历查找任意两点间是否相连,但是觉得还是并查集好理解些。。
至于怎么判断两条线段是否相交,有两种检验方法并行使用:
1.快速排斥检验:假设两条线段分别为P1P2,Q1Q2,分别以二者为对角线坐两个矩形,若两矩形都不相交,那么这两条线段必然不相交(当然如果相交了还得用第二种检验方法强化)
                而代码如何实现呢?其实也很简单,画图分析可以知道实际上就是P1P2的横坐标较小者不大于Q1Q2横坐标较大者且反之亦然并且P1P2的纵坐标较小者不小于Q1Q2
                纵坐标较大者,反之也亦然,满足这四种情况,可以初步暂时将两线段视为相交,并进入下一步的检验。
2.跨立检验:如果两条线段相交,那么这两条线段一定相互跨立。
            如果互相跨立首先,向量Q1P1 向量Q1P2 必然位于向量Q1Q2两侧,用叉乘的知识可以写出:(向量Q1P1)×(向量Q1Q2)·(向量Q1P2)×(向量Q1Q2)<0
            然后改写成(向量Q1P1)×(向量Q1Q2)·(向量Q1Q2)×(向量Q1P2)>0而当(向量Q1P1)×(向量Q1Q2)=0说明两向量共线又因为通过了1的检验则可以知道
            P1在Q1Q2上,同理后者由P2在Q1Q2上。综上可以知道若P1P2跨立Q1Q2则:(向量Q1P1)×(向量Q1Q2)·(向量Q1Q2)×(向量Q1P2)>=0 而Q1Q2跨立P1P2有
           (向量P1Q1)×(向量P1P2)·(向量P1P2)×(向量P1Q2)>=0
同时满足以上两个实验的检验,才能证明两条线段相交,然后用并查集对这些线段预处理,查询的时候直接就可以通过先祖是否相同来判断线段是否相交了。
代码如下:


#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

struct point{

double x;
double y;
};

struct seg{
point a;
point b;
};

seg p[20];
int pre[20];

void init(int x)
{

    pre[x]=x;
}

int find(int x)
{

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

        pre[x]=find(pre[x]);
    return  pre[x];
}

void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        pre[fx]=fy;
    }
}

double chaji(point a,point b,point c)
{

    return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}

int check(seg u,seg v)
{
     return       ((max(u.a.x,u.b.x)>=min(v.a.x,v.b.x))&&
                  (max(v.a.x,v.b.x)>=min(u.a.x,u.b.x))&&
                  (max(u.a.y,u.b.y)>=min(v.a.y,v.b.y))&&
                  (max(v.a.y,v.b.y)>=min(u.a.y,u.b.y))&&
                  (chaji(v.a,u.b,u.a)*chaji(u.b,v.b,u.a)>=0)&&
                  (chaji(u.a,v.b,v.a)*chaji(v.b,u.b,v.a)>=0));
}


int main()
{
    int n,i,j;
    int a,b,x,y;
    while(cin>>n)
    {

        if(n==0) break;
        for(i=1;i<=n;i++)
        {
            init(i);
        }
        for(i=1;i<=n;i++)
        {
            cin>>p[i].a.x>>p[i].a.y>>p[i].b.x>>p[i].b.y;
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i!=j&&check(p[i],p[j]))
                {
                    x=find(i);
                    y=find(j);
                    join(x,y);
                }
            }
        }
        while(cin>>a>>b)
        {
            if(a==b&&b==0)
                break;
            if(a==b)
            {
                cout<<"CONNECTED"<<endl;
            }
            else
            {
                x=find(a);
                y=find(b);
                if(x==y)
                {
                    cout<<"CONNECTED"<<endl;
                }
                else
                {
                    cout<<"NOT CONNECTED"<<endl;
                }
            }
        }
    }



    return 0;
}



×

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值