简单的计算几何题,判断两线段是否相交。将相交的两线段使用并查集归到一类中。查询时输出线段对应集合中元素的个数。
#include<stdio.h> struct Point{
double x,y;
};
struct Segment{
Point s,e;
}node[1010];
int n,parent[1010];
int getAbs(int value)
{
if(value>=0)return value;
return -value;
}
int getParent(int a){
while(parent[a]>0)a=parent[a];
return a;
}
void Union(int a,int b)
{
int r1 = getParent(a);
int r2 = getParent(b);
if(r1!=r2)
{
if(r1<r2)
{
parent[r1]+=parent[r2];//合并两个集合时,计算两个集合的元素个数
parent[r2]=r1;
}else{
parent[r2]+=parent[r1];
parent[r1]=r2;
}
}
}
double max(double a,double b)
{
if(a>=b)return a;
return b;
}
double min(double a,double b)
{
if(a>=b)return b;
return a;
}
/**
* 计算向量 ps,pe的叉积
*/
double multiply(Point p,Point s,Point e)
{
return (s.x-p.x)*(e.y-p.y)-(e.x-p.x)*(s.y-p.y);
}
int main()
{
int t,n,i,j,num,cnt;
char command;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
cnt=0;
//初始时每个元素都是一个集合
for(i=1;i<=n;i++)parent[i]=-1;
for(i=1;i<=n;i++)
{
getchar();
scanf("%c",&command);
if(command=='P'){
cnt++;
scanf("%lf%lf%lf%lf",&node[cnt].s.x,&node[cnt].s.y,&node[cnt].e.x,&node[cnt].e.y);
for(j=1;j<cnt;j++)
{
//判断第cnt个线段是否与前面的cnt-1个线段有相交。
if(max(node[cnt].s.x,node[cnt].e.x)>=min(node[j].s.x,node[j].e.x)
&& max(node[j].s.x,node[j].e.x)>=min(node[cnt].s.x,node[cnt].e.x)
&& max(node[cnt].s.y,node[cnt].e.y)>=min(node[j].s.y,node[j].e.y)
&& max(node[j].s.y,node[j].e.y)>=min(node[cnt].s.y,node[cnt].e.y)
&& multiply(node[cnt].s,node[j].s,node[j].e)*multiply(node[cnt].e,node[j].s,node[j].e)<=0
&& multiply(node[j].s,node[cnt].s,node[cnt].e)*multiply(node[j].e,node[cnt].s,node[cnt].e)<=0)
{
//有相交就合并集合
Union(cnt,j);
}
}
}else
{
scanf("%d",&num);
//当parent为负数时,其绝对值就是该集合的元素个数。
printf("%d\n",getAbs(parent[getParent(num)]));
}
}
if(t!=0)
{
printf("\n");
}
}
return 0;
}