hdu 1558 Segment set(判线段相交模版)

解决线段集查询问题,通过并查集算法判断线段是否相连,并查询特定线段所在集合大小。输入包括多组测试数据,每组数据包含多个命令,命令包括绘制线段和查询线段集大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Segment set

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2644    Accepted Submission(s): 994


Problem Description
A segment and all segments which are connected with it compose a segment set. The size of a segment set is the number of segments in it. The problem is to find the size of 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 in the 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.
 

Sample Input
1 10 P 1.00 1.00 4.00 2.00 P 1.00 -2.00 8.00 4.00 Q 1 P 2.00 3.00 3.00 1.00 Q 1 Q 3 P 1.00 4.00 8.00 2.00 Q 2 P 3.00 3.00 6.00 -2.00 Q 5
 

Sample Output
1 2 2 2 5
并查集水题,这题要判线段相交。
AC代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <vector>
#include <cstdlib>
#define eps 1e-8
using namespace std;
const int MAX=1005;
int father[MAX],rank[MAX];
struct node
{
    double x1,y1;
    double x2,y2;
} line[1010];
int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}
double multiply1(node a,node b)
{
    return (a.x1-a.x2)*(b.y1-a.y1)-(a.y1-a.y2)*(b.x1-a.x1);
}
double multiply2(node a,node b)
{
    return (a.x1-a.x2)*(b.y2-a.y1)-(a.y1-a.y2)*(b.x2-a.x1);
}
bool inter(node a,node b)
{
    if(max(a.x1,a.x2)>=min(b.x1,b.x2)&&
            max(b.x1,b.x2)>=min(a.x1,a.x2)&&
            max(a.y1,a.y2)>=min(b.y1,b.y2)&&
            max(b.y1,b.y2)>=min(a.y1,a.y2)&&
            multiply1(a,b)*multiply2(a,b)<=eps&&
            multiply1(b,a)*multiply2(b,a)<=eps)
        return true;
    else return false;
}
int Find_set(int n)
{
    if(n!=father[n])
        father[n]=Find_set(father[n]);
    return father[n];
}
void Union(int a,int b)
{
    a=Find_set(a);
    b=Find_set(b);
    if(a==b) return;
    father[b]=a;
    rank[a]+=rank[b];
}
void init()
{
    for(int i=0; i<MAX; i++)
    {
        father[i]=i;
        rank[i]=1;
    }
}
int main()
{
    int t,n,m;
    char s[2];
    scanf("%d",&t);
    while(t--)
    {
        init();
        int cnt=1;
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",s);
            if(s[0]=='P')
            {
                scanf("%lf%lf%lf%lf",&line[cnt].x1,&line[cnt].y1,&line[cnt].x2,&line[cnt].y2);
                for(int i=1; i<cnt; i++)
                    if(inter(line[i],line[cnt]))
                        Union(i,cnt);
                cnt++;
            }
            else
            {
                scanf("%d",&m);
                int root=Find_set(m);
                printf("%d\n",rank[root]);
            }
        }
        if(t>0)
        printf("\n");
    }
    return 0;
}



HDU(Hangzhou Dianzi University)OJ 中经常涉及到几何计算的问题,其中“断两条线段是否相交”是一个经典的算法问题。以下是关于如何断两线段是否相交的基本思路及其实现步骤: ### 断两条线段相交的核心思想 可以利用向量叉积以及端点位置的关系来确定两条线段是否相交。 #### 具体步骤: 1. **定义基本概念** - 假设两条线段分别为 `AB` 和 `CD`。 - 使用二维平面中的坐标表示各顶点:A(x₁,y₁), B(x₂,y₂),C(x₃,y₃) ,D(x₄,y₄)。 2. **叉积的作用** 叉积可以帮助我们了解两点相对于一条直线的位置关系。 对于三个点 P、Q、R ,我们可以用叉乘 `(Q-P)x(R-P)` 来检测 R 是否在 QP 直线的一侧还是另一侧。 如果结果为正数,则表明顺时针;如果负则逆时针;若等于0则共线。 3. **快速排斥实验** 首先做一个矩形包围盒测试——即检查两个线段所在的最小外接矩形是否有重叠区域。如果没有重叠直接定为不相交。 4. **跨立试验 (Cross-over Test)** 确认每个线段的两端分别位于另一个线段两侧即可认为它们交叉了。这通过上述提到过的叉积运算完成。 5. **特殊情况处理** 包含但不限于如下的几种情况需要单独讨论: - 完全重合的部分; - 存在一个公共端点但并不完全穿过等边缘状况。 6. **代码框架示例(Pseudo code):** ```python def cross_product(p1,p2,p3): return (p2[0]-p1[0])*(p3[1]-p1[1])-(p2[1]-p1[1])*(p3[0]-p1[0]) def on_segment(p,q,r): if ((q[0] <= max(p[0], r[0])) and (q[0] >= min(p[0], r[0])) and (q[1] <= max(p[1], r[1])) and (q[1] >= min(p[1], r[1]))): return True; return False; def do_segments_intersect(A,B,C,D): # 计算四个方向的叉积值 o1 = cross_product(A, C, B) o2 = cross_product(A, D, B) o3 = cross_product(C, A, D) o4 = cross_product(C, B, D) # 标准情况断 if(o1 !=o2 && o3!=o4): return True # 特殊情况逐一验证... ``` 7. 最终结合所有条件得出结论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值