Segment set
TimeLimit: 3000/1000 MS (Java/Others) Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 5359 Accepted Submission(s): 2064
ProblemDescription
A segmentand all segments which are connected with it compose a segment set. The size ofa segment set is the number of segments in it. The problem is to find the sizeof 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 inthe 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.
SampleInput
1
10
P 1.001.00 4.00 2.00
P 1.00-2.00 8.00 4.00
Q 1
P 2.003.00 3.00 1.00
Q 1
Q 3
P 1.004.00 8.00 2.00
Q 2
P 3.003.00 6.00 -2.00
Q 5
SampleOutput
1
2
2
2
5
Author
LL
Source
HDU2006-12 Programming Contest
Recommend
LL
LL
算法分析:
题意:给几条线段,动态输出条线段所在的集合中包含的线段的个数
算法:并查集+快速排斥实验&跨立实验(点这里) 判断两直线是否相交(相交合并即可)
代码实现:
#include<bits/stdc++.h> using namespace std;; #define N 1005 int fa[N],num[N]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } struct point{ double x,y; }P1,P2,Q1,Q2; struct Edge { point a,b; }e[N]; double xmult(point a,point b,point c) //大于零代表a,b,c左转 { return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); } bool OnSegment(point a,point b,point c) //a,b,c共线时有效 { return c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x)&&c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y); } bool Cross(point a,point b,point c,point d) //判断ab 与cd是否相交 { double d1,d2,d3,d4; d1=xmult(c,d,a); d2=xmult(c,d,b); d3=xmult(a,b,c); d4=xmult(a,b,d); if(d1*d2<0&&d3*d4<0) return 1; else if(d1==0&&OnSegment(c,d,a)) return 1; else if(d2==0&&OnSegment(c,d,b)) return 1; else if(d3==0&&OnSegment(a,b,c)) return 1; else if(d4==0&&OnSegment(a,b,d)) return 1; return 0; } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { num[i]=1;fa[i]=i; } int sum=0; char s[5]; for(int i=1;i<=n;i++) { scanf("%s",s); if(s[0]=='P') { sum++; scanf("%lf%lf%lf%lf",&e[sum].a.x,&e[sum].a.y,&e[sum].b.x,&e[sum].b.y); for(int j=1;j<sum;j++) { if(find(j)!=find(sum)&&Cross(e[sum].a,e[sum].b,e[j].a,e[j].b)) { //cout<<sum<<" "<<j<<endl; int r1=find(sum),r2=find(j); if(r1!=r2) { //cout<<r1<<" "<<r2<<endl; fa[r1]=r2; num[r2]+=num[r1];//注意r2才是父亲节点 } } } } else { int t; scanf("%d",&t); printf("%d\n",num[find(t)]);//找他的父亲节点的集合线段数 } } if(T)//每个测试用例要输出空行,注意最后一个样例不用输出空行 printf("\n"); } return 0; }