• 判断两个线段是否相交


    题目

    段和与其连接的所有段组成段组。段集的大小是其中的段的数量。问题是要找到一些段集的大小。 

    输入在第一行中有一个整数t - 测试用例的数量。对于第一行中的每个测试用例,都有一个整数n(n <= 1000) - 命令的数量。 

    有两种不同的命令以不同的格式描述如下: 

    P x1 y1 x2 y2 - 绘制两个端点坐标为(x1,y1),(x2,y2)的线段。 
    Q k - 查询包含第k个分段的分段集合的大小。 

    k在1和当前片段的数量之间。起初飞机上没有任何部分,所以第一个命令总是一个P命令。 
    产量对于每个Q命令,输出答案。测试用例之间有空行

    示例输入

    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
    示例输出
    1
    2
    2
    2
    5
    题意:是求第几个点相交的几个直线个数
    判断两个线段是否相交

    对于线段A,B,如果 线段A与直线B相交 ,线段B与直线A相交 ,那么就可以认为线段A 和线段B相交。

    关键问题是:如何判断直线AB是否与线段CD相交呢?

    设直线AB的方程为:f(x,y) = 0,直线方程可以通过两点式求得。

    当C和D点不在直线的同侧时,直线AB必然与线段CD相交,也就是说直线AB与线段CD相交的条件为:f(C) * f(D) <= 0。

    注意:算每个集合中有多少个元素,只要再单独维护一个数组,开始都是值为1,因为开始集合中都只有本身,然后合并一个集合的时候把数组值相加就行

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    struct sss
    {
        double x1,x2,y1,y2;
    }mp[1001];
    
    int t,n;
    int pre[1001];
    int num[1001];
    
    int suan(struct sss x,struct sss y)
    {
        double f1=(y.x1-x.x1)/(x.x1-x.x2)-(y.y1-x.y1)/(x.y1-x.y2);
        double f2=(y.x2-x.x1)/(x.x1-x.x2)-(y.y2-x.y1)/(x.y1-x.y2);
        if(f1*f2<=0)
        return 1;
        return 0;
    }
    
    int pan(struct sss x,struct sss y)
    {
        if(!suan(x,y))
        return 0;
        if(!suan(y,x))
        return 0;
        return 1;
    }
    
    int find(int x)
    {
        if(x==pre[x]) return x;
        return pre[x]=find(pre[x]);
    }
    
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            char c;
            int m=0;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
             pre[i]=i,num[i]=1; 
            for(int i=1;i<=n;i++)
            {
                cin>>c;
                if(c=='P')
                {
                    m++;
                    cin>>mp[m].x1>>mp[m].y1>>mp[m].x2>>mp[m].y2;
                    for(int j=1;j<m;j++)
                    {
                        int xx=find(j);
                        int yy=find(m);
                        if(xx!=yy)
                        {
                            if(pan(mp[m],mp[j]))
                            {
                                pre[xx]=yy;
                                num[yy]+=num[xx];
                            }
                        }
                    }
                }
                else{
                    int x;
                    scanf("%d",&x);
                    x=find(x);
                    printf("%d
    ",num[x]);
                }
            }
            if(t!=0)
            printf("
    ");
        }
    }
     
  • 相关阅读:
    01快速入门-03-条件判断和循环
    01快速入门-02-数组和对象
    01快速入门-01-基本语法和数据类型
    《Head First 设计模式》[01] 策略模式
    爬山算法与模拟退火算法的分析与实现
    Java虚拟机(二) —— 运行时数据区的OOM异常
    CoreJava(一)—— Java迭代语句
    Java虚拟机(二) —— 垃圾回收算法与垃圾回收器
    算法学习 —— 使用Linux C++练习OJ
    Java虚拟机(一) —— 运行时数据区
  • 原文地址:https://www.cnblogs.com/Lis-/p/8988509.html
Copyright © 2020-2023  润新知