题目的大概意思是只要两个线段连在一起就可以算在一个集合里面,问第k条直线处在的集合中有多少条直线。
假设在已知判断线段相交的方法的情况下,把一条新的直线放到平面上的时候,我们把这条直线和之前的所有直线判定一遍,假若相交,则合并这两个集合,因为n<=1000,顶多也只有1000条直线,时间还是可以承受的。。况且假若不一一比较的话,也没什么简单的办法来获得我们需要的信息。。。
接下来就是解决判定线段相交的问题了,借用了算法导论上的办法,以下是代码:
#include<cstdio>
#include<utility>
#include<cmath>
#include<algorithm>
using namespace std;
typedef pair<double,double> point;
struct line{
point p1,p2;
line(double a=0,double b=0,double c=0,double d=0):p1(make_pair(a,b)),p2(make_pair(c,d)){};
}te,arr[1010];
int t,n,qu,cou=1,sets[1010],sz[1010];
char c;
int _find(int x){return (x==sets[x])?x:sets[x]=_find(sets[x]);}
bool _merge(int x,int y),judge(const line&,const line&),on_segment(const point&,const point&,const point&);
double direction(const point&,const point&,const point&);
int main(){
scanf("%d",&t);
for(int times=1;times<=t;++times){
scanf("%d%*c",&n);
while(n--){
scanf("%c",&c);
if(c=='Q'){
scanf("%d%*c",&qu);
printf("%d\n",sz[_find(qu)]);
}
else{
sets[cou]=cou,sz[cou]=1;
scanf("%lf%lf%lf%lf%*c",&te.p1.first,&te.p1.second,&te.p2.first,&te.p2.second);
// printf("%lf %lf %lf %lf\n",te.p1.first,te.p1.second,te.p2.first,te.p2.second);
arr[cou]=te;
for(int i=1;i<cou;++i){
if(judge(arr[i],te))
_merge(i,cou);//printf("%s\n",(_merge(i,cou)?"success":"failed"));
}
++cou;
}
}
cou=1;
if(times!=t)
printf("\n");
}
return 0;
}
bool _merge(int x,int y){
int a=_find(x),b=_find(y);
if(a!=b)
sz[a]+=sz[b],sets[b]=a;
return a!=b;
}
bool judge(const line&a,const line& b){
double d1=direction(b.p1,b.p2,a.p1),d2=direction(b.p1,b.p2,a.p2),d3=direction(a.p1,a.p2,b.p1),d4=direction(a.p1,a.p2,b.p2);
// printf("%lf %lf %lf %lf\n",d1,d2,d3,d4);
if(((d1>1E-5&&d2<-1E-5)||(d1<-1E-5&&d2>1E-5))&&((d3>1E-5&&d4<-1E-5)||(d3<-1E-5&&d4>1E-5)))
return true;
else if(fabs(d1)<1E-5&&on_segment(b.p1,b.p2,a.p1))
return true;
else if(fabs(d2)<1E-5&&on_segment(b.p1,b.p2,a.p2))
return true;
else if(fabs(d3)<1E-5&&on_segment(a.p1,a.p2,b.p1))
return true;
else if(fabs(d4)<1E-5&&on_segment(a.p1,a.p2,b.p2))
return true;
else
return false;
}
double direction(const point&a,const point&b,const point& c){
return (c.first-a.first)*(b.second-a.second)-(b.first-a.first)*(c.second-a.second);
}
bool on_segment(const point&a,const point&b,const point& c){
return min(a.first,b.first)<=c.first&&c.first<=max(a.first,b.first)&&min(a.second,b.second)<=c.second&&c.second<=max(a.second,b.second);
}
函数说明:_find函数是查找元素同时自带路径压缩的写法
_merge函数用于合并两个集合,其实在这里返回值完全可以不要,只是我利用返回值找出了编写时的一个小bug。
judge函数用于判断两个线段是否相交,我为了迎合算法导论上的写法,所以参数是那么写的,,当然了,要直接拿去用也可以。
direction函数和on_segment函数也解释一下吧,direction函数用于返回两个向量的叉积,具体的算法导论上面有,大概意思就是判断方向,要求两条向量各在两侧
on_segment函数用于处理一条线段的端点恰好处于另一条线段上的情况