使用并查集,每输入一条线段,从头扫描已输入的所有线段,找到与新输入线段相交的线段,合并两者。
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 1005;
int father[MAXN];
struct Segment //线段
{
double x1, y1, x2, y2;
}seg[MAXN];
//判断线段s1的两端点是否位于线段s2的两侧
bool judge(Segment s1, Segment s2)
{
double m = (s2.x2 - s2.x1) * (s1.y1 - s2.y1) - (s2.y2 - s2.y1) * (s1.x1 - s2.x1);
double n = (s2.x2 - s2.x1) * (s1.y2 - s2.y1) - (s2.y2 - s2.y1) * (s1.x2 - s2.x1);
if (m * n <= 0)
return true;
else
return false;
}
//初始化并查集
void makeSet(int n)
{
for (int i = 0; i <= n; i++)
father[i] = i;
}
//查找x所在集合的代表元素(所在树的根结点)
int find(int x)
{
if (x != father[x])
father[x] = find(father[x]);
return father[x];
}
//合并x所在集合和y所在集合
void unionSet(int x, int y)
{
int fx = find(x);
int fy = find(y);
if (fx != fy)
father[fx] = fy;
}
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
makeSet(n);
int num = 1; //线段数目
char c;
for (int i = 0; i < n; i++)
{
cin >> c;
if (c == 'P')
{
cin >> seg[num].x1 >> seg[num].y1 >> seg[num].x2 >> seg[num].y2;
for (int j = 1; j < num; j++) //扫描已输入的所有线段
{
//判断两线段是否相交
if (judge(seg[num], seg[j]) && judge(seg[j], seg[num]))
unionSet(num, j);
}
++num;
}
else
{
int count = 0; //与第k条线段相交的线段数量
int k;
cin >> k;
int fk = find(k);
for (int j = 0; j < num; j++) //计算与第k条线段在同一集合的线段数量
{
if (find(j) == fk)
++count;
}
cout << count << endl;
}
}
if (T)
cout << endl;
}
return 0;
}
继续加油。