线段合并sicily1004

题目描述

大致意思就是给出n对坐标点,每对组成一个线段。如果两个线段有重合的部分则两条线段可以合并为一条(或者两条线段端点相连,斜率相同也可以合并),求最后剩下几条。

输入

一个n表示n条线段,然后又n行,每行四个浮点数,两个数为一个坐标,两个坐标表示一条线段。

输出

输出剩下的线段条数

思路

先对输入进行排序,没有斜率的时候,y值小的储存在前;有斜率(包括斜率为0),x值小的储存在前。

然后从第一条和后边的n-1条进行比较,有重合的就进行合并,然后再比第二条,以此直到最后两条线段的比较。

数据结构:用了一个线段类,其实是复杂了。

 

代码

/*
    在一堆线段中找出重合的那些,并合并。
    输出最后剩下几条线段。
    放到sicily上超时。应该还能改进。
*/
#include<cmath>
#include<iostream>
#include<vector>


const double ERRORS = 0.000001;
//判断两个浮点数是否相等
bool isequal(double a, double b) {
    if (fabs(a - b) < ERRORS) {
        return true;
    }
    else {
        return false;
    }
}
//线段类,主要用来判断两条线段是否重合,组合重合的线段
class LineSegment
{
public:
    LineSegment() {};
    LineSegment(double, double, double, double);
    ~LineSegment() {};
    void combine(LineSegment);
    bool isCoincide(LineSegment);
private:
    double x[2];
    double y[2];
    double slope;//线段的斜率
    double x0;//与y轴的交点
    bool o_slope;
};
//含参构造函数
LineSegment::LineSegment(double x1, double x2, double y1, double y2) {
    if (isequal(x1, x2)) {
        o_slope = false;//如果不存在斜率
        x[0] = x[1] = x1;
        //斜率不存在的情况下y值小的认为是首端点
        if ((!isequal(y1, y2)) && y1 < y2) {
            y[0] = y1;
            y[1] = y2;
        }
        else {
            y[0] = y2;
            y[1] = y1;
        }
        x0 = x1;
    }
    else{
        o_slope = true;
        if (x1 < x2) {//斜率存在的情况下,x值小的认为是首端点
            x[0] = x1;
            x[1] = x2;
            y[0] = y1;
            y[1] = y2;
        }
        else{
            x[0] = x2;
            x[1] = x1;
            y[0] = y2;
            y[1] = y1;
        }
        //计算斜率和与y轴的交点
        slope = (y2 - y1) / (x2 - x1);
        x0 = y1 - x1 * slope;
    }
}
//判断两条线段是否重合
bool LineSegment::isCoincide(LineSegment t) {
    if ((!o_slope)) {//如果斜率不存在
        if (t.o_slope|| (!isequal(x0, t.x0))) {//另一条线段有斜率或者两条线段的x值不同,不重合
            return false;
        }
        else{
            if ((y[0] > t.y[1] && (!isequal(y[0],t.y[1]))) || (y[1] < t.y[0] && (!isequal(y[1], t.y[0])))){//一条线段的最高点比另一条的最低点还要低,则不重合。判断不相等是为了排除误差
                return false;
            }
            else{
                return true;
            }
        }
    }
    else {
        if (!isequal(slope, t.slope)|| !isequal(x0, t.x0)) {//斜率存在但不相等或者斜率相等但是与y轴交点不相等,不重合
            return false;
        }
        else{
            if ((x[0] > t.x[1] && (!isequal(x[0],t.x[1]))) || (x[1] < t.x[0] && (!isequal(x[0], t.x[1])))) {//一条线段的最大的x比另一条最小的x还小,则不重合。判断不相等时为了排除误差干扰
                return false;
            }
            else {
                return true;
            }
        }
    }
}

void LineSegment::combine(LineSegment t) {
    if (!o_slope) {//没有斜率的情况下
        if (y[1] < t.y[1]) {//尾端点为两个尾端点中较大的那个
            y[1] = t.y[1];
        }
        if (y[0] > t.y[0]) {//首端点为两个首端点中较小的那个
            y[0] = t.y[0];
        }
    }
    else{
        if (x[1] < t.x[1]) {//有斜率时,尾端点为两个尾端点中x值大的那个
            x[1] = t.x[1];
            y[1] = t.y[1];
        }
        if (x[0] > t.x[0]) {//首端点为两个首端点中小的那个
            x[0] = t.x[0];
            y[0] = t.y[0];
        }
    }
}
int main() {
    using std::cin;
    using std::cout;
    using std::endl;
    int n;
    cin >> n;
    while (n != 0) {
        double a1, b1, a2, b2;
        std::vector<LineSegment> ls;//定义一个向量
        for (int i = 0; i < n; i++) {
            cin >> a1 >> b1 >> a2 >> b2;
            ls.push_back(LineSegment(a1, a2, b1, b2));//将线段输入向量
        }
        int result = n;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {//对第i个线段,从i+1开始判断,直到n。
                if (ls[i].isCoincide(ls[j])) {//如果重合
                    ls[j].combine(ls[i]);//合并
                             result—;
                 }
            }
        }
        cout << result << endl;
        cin >> n;
    }
}

转载于:https://www.cnblogs.com/aguoshaofang/p/4996680.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值