hdu 1558 Segment set (并查集+计算几何)

Segment set

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3486    Accepted Submission(s): 1297

Problem Description

A segment and all segments which are connected with it compose a segment set. The size of a segment set is the number of segments in it. The problem is to find the size of some segment set.

Input

In the first line there is an integer t - the number of test case. For each test case in first line there is an integer n (n<=1000) - the number of commands.

There are two different commands described in different format shown below:

P x1 y1 x2 y2 - paint a segment whose coordinates of the two endpoints are (x1,y1),(x2,y2).

Q k - query the size of the segment set which contains the k-th segment.

k is between 1 and the number of segments in the moment. There is no segment in the plane at first, so the first command is always a P-command.

Output

For each Q-command, output the answer. There is a blank line between test cases.

Sample Input

1
10
P 1.00 1.00 4.00 2.00
P 1.00 -2.00 8.00 4.00
Q 1
P 2.00 3.00 3.00 1.00
Q 1
Q 3
P 1.00 4.00 8.00 2.00
Q 2
P 3.00 3.00 6.00 -2.00
Q 5

Sample Output

1
2
2
2
5

线段相交分为两种情况:一、线段相互交叉,即相互跨立 。二、一条线段的某个端点在另一条线段上。

double cross(point a,point b,point c)      //叉积判断点与直线位置关系
{                                          //若点在直线逆时针方向,返回正值
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

若点在直线上(线段上或者延长线上)返回值为零。

bool ifin(point a,point b,point c)   //判断点是否在线段上
{
    if(c.x>=min(a.x,b.x)&&c.y>=min(a.y,b.y)&&
       c.x<=max(a.x,b.x)&&c.y<=max(a.y,b.y))
        return true;
    return false;
}

则判断线段是否相交,可用下面算法:

bool judge(point a,point b,point c,point d)
{
    //快速排斥实验,不想交返回0
    if(cross(a,b,c)==0&&ifin(a,b,c))
        return true;
    else if(cross(a,b,d)==0&&ifin(a,b,d))
        return true;
    else if(cross(c,d,a)==0&&ifin(c,d,a))
        return true;
    else if(cross(c,d,b)==0&&ifin(c,d,b))
        return true;
    //跨立实验,线段ab的两端点在cd两端,且线段cd的两端点在线段ab两端
    if(cross(a,b,c)*cross(a,b,d)<0&&cross(c,d,a)*cross(c,d,b)<0)
        return true;
    return false;
}

思路:每次得到一条线段判断和前面所有线段是否相交,运用并查集相关操作,得到答案。

#include"stdio.h"
#include"string.h"
#include"math.h"
#include"vector"
#include"iostream"
#include"algorithm"
using namespace std;
#define N 1005
const int inf=0x7fffffff;
int pre[N],num[N];
struct point
{
    double x,y;
};
struct node
{
    point p1,p2;
}f[N];
double cross(point a,point b,point c)      //叉积判断点与直线位置关系
{                                          //若点在直线逆时针方向,返回正值
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
bool ifin(point a,point b,point c)
{
    if(c.x>=min(a.x,b.x)&&c.y>=min(a.y,b.y)&&
       c.x<=max(a.x,b.x)&&c.y<=max(a.y,b.y))
        return true;
    return false;
}
bool judge(point a,point b,point c,point d)
{
    //快速排斥实验,不想交返回0
    if(cross(a,b,c)==0&&ifin(a,b,c))
        return true;
    else if(cross(a,b,d)==0&&ifin(a,b,d))
        return true;
    else if(cross(c,d,a)==0&&ifin(c,d,a))
        return true;
    else if(cross(c,d,b)==0&&ifin(c,d,b))
        return true;
    //跨立实验,线段ab的两端点在cd两端,且线段cd的两端点在线段ab两端
    if(cross(a,b,c)*cross(a,b,d)<0&&cross(c,d,a)*cross(c,d,b)<0)
        return true;
    return false;
}
int findx(int x)
{
    if(x!=pre[x])
        pre[x]=findx(pre[x]);
    return pre[x];
}
void unionset(int a,int b)
{
    int f1,f2;
    f1=findx(a);
    f2=findx(b);
    if(f1!=f2)
    {
        pre[f1]=f2;
        num[f2]+=num[f1];
    }
}
int main()
{
    int T,n,i,j,k,x;
    char ch;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            pre[i]=i;
            num[i]=1;
        }
        for(i=1,j=1;i<=n;i++)
        {
            getchar();
            scanf("%c",&ch);
            if(ch=='Q')
            {
                scanf("%d",&x);
                int xx=findx(x);
                printf("%d\n",num[xx]);
            }
            else
            {
                scanf("%lf%lf%lf%lf",&f[j].p1.x,&f[j].p1.y,&f[j].p2.x,&f[j].p2.y);
                for(k=1;k<j;k++)
                {
                    if(judge(f[k].p1,f[k].p2,f[j].p1,f[j].p2))
                        unionset(k,j);
                }
                j++;
            }
        }
        if(T)
            puts("");
    }
    return 0;
}
时间: 2024-10-07 00:03:08

hdu 1558 Segment set (并查集+计算几何)的相关文章

hdu 1558 Segment set (并查集)

Segment set Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3907    Accepted Submission(s): 1471 Problem Description A segment and all segments which are connected with it compose a segment set

hdu 1558 (线段相交+并查集) Segment set

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1558 题意是在坐标系中,当输入P(注意是大写,我当开始就wa成了小写)的时候输入一条线段的起点坐标和终点坐标,当输入Q的时候输入n,然后输出与第n条线段相交的线段有多少条 首先判断线段是否相交,在算法导论p577上有介绍 线段A(x1,y1)-B(x2,y2),所在直线L1方程为F1(x,y)=0;线段C(x3,y3)-D(x4,y4),所在直线L2方程为F2(x,y)=0; 如何判断两条线段有交点:(

hdu 1558 线段相交+并查集路径压缩

Segment set Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3457    Accepted Submission(s): 1290 Problem Description A segment and all segments which are connected with it compose a segment set.

hdu 1558 线段相交+并查集

题意:要求相交的线段都要塞进同一个集合里 sol:并查集+判断线段相交即可.n很小所以n^2就可以水过 1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 int f[1010]; 8 char ch; 9 int tmp,n; 10 double X1,X2,Y1,Y2; 11 12 #def

HDU 1558 Segment set (并查集+线段非规范相交)

题目链接 题意 : 如果两个线段相交就属于同一集合,查询某条线段所属集合有多少线段,输出. 思路 : 先判断与其他线段是否相交,然后合并. 1 //1558 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <cmath> 6 #define eps 1e-8 7 #define zero(x) (((x) > 0 ? (x) : (-x)) < e

hdu 3234 Exclusive-OR (并查集+异或性质)

Exclusive-OR Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2177    Accepted Submission(s): 603 Problem Description You are not given n non-negative integers X0, X1, ..., Xn-1 less than 220 ,

HDU 4496 D-City (并查集)

题意:给你n个点m条边,问删除前i条边后有多少个连通分块. 思路:从后往前操作,从后往前添加i条边等于添加完m条边后删掉前m-i条边,可知刚开始没有边,所以sum[m]=n; #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <queue> #include <math.h> #define M 100010

hdu 1811Rank of Tetris (并查集 + 拓扑排序)

1 /* 2 题意:这些信息可能有三种情况,分别是"A > B","A = B","A < B",分别表示A的Rating高于B,等于B,小于B. 3 4 现在Lele并不是让你来帮他制作这个高手榜,他只是想知道,根据这些信息是否能够确定出这个高手榜,是的话就输出"OK". 5 否则就请你判断出错的原因,到底是因为信息不完全(输出"UNCERTAIN"),还是因为这些信息中包含冲突(输出&quo

HDU 1232 畅通工程(并查集)

畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 30485    Accepted Submission(s): 16013 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可以实现交通(但不一定有