HDU1558 - Segment set: http://acm.hdu.edu.cn/showproblem.php?pid=1558
题目大意: 输入一些线段的端点坐标,若两线段相交,则把他们合并成一个集合,输入数据里会有k,问和k线段相交的线段的数目(包括自己)
思路: 每次输入一条线段,都从头扫描一次. 找出之前输入的线段里面,所有和其相交的线段,并且合并(合并用的是线段的ID). 就是: 并查集 + 判断线段相交
代码:
#include <iostream>
#include <cstring>
#define maxn 1005
using namespace std;
int father[maxn];
struct point{
double x1,y1,x2,y2;
}p[maxn];//结构体储存线段的两个端点坐标
bool judge(point x,point y)//利用 叉积 判断线段相交
{
double m=(y.x2-y.x1)*(x.y1-y.y1)-(y.y2-y.y1)*(x.x1-y.x1);
double n=(y.x2-y.x1)*(x.y2-y.y1)-(y.y2-y.y1)*(x.x2-y.x1);
if(m*n<=0)return true;
return false;
}
int find(int x)
{
return x == father[x] ? x : father[x] = find(father[x]);
}
void join(int x,int y)
{
x=find(x),y=find(y);
if(x!=y)
father[x]=y;
}
int main()
{
int t,n,k;
int count,flag;
char s;
cin>>t;
while(t--)
{
for(int i=0;i<maxn;i++)father[i]=i;
cin>>n;
flag=1;//记录的是线段的数目
for(int i=0;i<n;i++)
{
cin>>s;
if(s=='P')
{
cin>>p[flag].x1>>p[flag].y1>>p[flag].x2>>p[flag].y2;
for(int j=1;j<flag;j++)//每次输入都从头开始扫描之前输入了的线段,判断当前线段是否会和他们相交
{
if(judge(p[flag],p[j])&&judge(p[j],p[flag]))//判断两线段是否相交
join(flag,j);//相交则将他们合并
}
flag++;
}else{
count=0;
cin>>k;
int x=find(k);
for(int j=0;j<flag;j++)//计算与k线段是同一集合的线段数目
if(find(j)==x)count++;
cout<<count<<endl;
}
}
if(t)cout<<endl;
}
return 0;
}