Segment set HDU - 1558
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
题意:t组输入,每组一个数m,表示m次操作。接下来m行,每行先输入一个字符ok,若ok==‘P’,则表示添加线段,然后紧接着输入线段的两个坐标;如果ok==‘Q’,再输入一个数k,表示询问与k所在的集合中有多少条线段。每个测试用例之间有一个空白行。
分析:首先,我们肯定要判断两条线段是否相交,如何判断呢?代码中给出的方法并不是规范的判断方法。其次,就是要进行集合操作,很自然的就想到了并查集。我们可以开两个数组,pre数组就是普通的根结点数组,而num数组是为了统计根结点所在结合的线段数。在每次添加一条线段时,我们要判断该线段是否跟以前的线段有交点,如果有交点,则进行unionn操作,即合并。在unionn函数中,如果两个参数的根结点不同,则合并,并且num数组也得发生变化。
注:最后一个测试用例之后没有空白行。
代码:
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
struct point{
double x,y;
};
struct line{
point a,b;
}l[1005];
int pre[1005],num[1005];
const double EPS=1e-10;
void init()
{
for(int i=0;i<1005;i++)
{
pre[i]=i;
num[i]=1;//一开始每个集合只有一个线段,就是自己
}
}
bool judge(line l1,line l2)//判断两个线段是否相交
{
point p1,p2,p3,p4;
p1=l1.a;p2=l1.b;
p3=l2.a;p4=l2.b;
if( min(p1.x,p2.x)>max(p3.x,p4.x) ||
min(p1.y,p2.y)>max(p3.y,p4.y) ||
min(p3.x,p4.x)>max(p1.x,p2.x) ||
min(p3.y,p4.y)>max(p1.y,p2.y) )
return 0;
double k1,k2,k3,k4;
k1 = (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x);
k2 = (p2.x-p1.x)*(p4.y-p1.y) - (p2.y-p1.y)*(p4.x-p1.x);
k3 = (p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x);
k4 = (p4.x-p3.x)*(p2.y-p3.y) - (p4.y-p3.y)*(p2.x-p3.x);
return (k1*k2<=EPS && k3*k4<=EPS);
}
int find(int x)
{
while(x!=pre[x])
x=pre[x];
return x;
}
void unionn(int x,int y)
{
int r1=find(x);
int r2=find(y);
if(r1!=r2)
{
pre[r2]=r1;
num[r1]+=num[r2];
}
}
int main()
{
int t,m,cnt,k;
char ok;
cin>>t;
while(t--)
{
cin>>m;
cnt=0;
init();
for(int i=0;i<m;i++)
{
cin>>ok;
if(ok=='P')
{
cnt++;
cin>>l[cnt].a.x>>l[cnt].a.y>>l[cnt].b.x>>l[cnt].b.y;
for(int j=1;j<cnt;j++)//j从1开始,不能从0开始
{
if(judge(l[cnt],l[j]))
unionn(cnt,j);
}
}
else if(ok=='Q')
{
cin>>k;
int root=find(k);
cout<<num[root]<<endl;
}
}
if(t)//注意格式
cout<<endl;
}
return 0;
}