soj.1004 I Conduit!

问题介绍:输入一堆以两点确认的线段,要求你通过判断那些线段是重叠的,然后给出一个最终实际多少条直线


问题剖析:这道题有两个需要解决的问题。1、怎样判断两条线是重合的,2、关于单精度浮点数与双精度浮点数的精确度问题

  而第一个问题,我采用给每条线段计算其斜率、截距,以及其开始点与结束点的x值(需要考虑斜率不存在的情况,此时斜率保存为无限大,截距保存为x坐标,记录开始点与结束点的y值),然后通过每条线段的对比,首先是斜率、截距是否相同,再之其结束点是否在另一条直线的开始点之后。

  而第二个问题,我用一个宏定义将EPS赋值1e-7,这代表了单精度浮点数的最大精确度,然后用自己的比较函数,判断两点差值是否小于这个值,来确保精确度的问题。

  我在这道题使用了vector的数据结构,理由为vector提供的函数begin(),end(),这个两个都是返回random access iterator,才能满足stl里sort函数的使用,而list的begin(),end()返回的只是bidirection iterator,也试想过用set这个可以自动排序的容器,但是其加入项的方法比较麻烦。


下面是我的代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define INF 1e+15
#define EPS 1e-7

int compare(double x1, double x2) {  // float compare
  if (x1 - x2 < -EPS)
    return -1;
  if (x1 - x2 > EPS)
    return 1;
  return 0;
}

class Line {
 private:
  double start;
  double end;
  double k;
  double b;
 public:
  Line() {}
  Line(double sx, double sy, double ex, double ey) {
    if (compare(ex, sx) == 0) {
      k = INF;  // if k is not exist, put an infinite
      b = sx;
      start = sy;  // store the number of y
      end = ey;
    } else {
      k = (ey - sy) / (ex - sx);
      b = sy - k * sx;
      start = sx;
      end = ex;
    }
  }
  Line(const Line& l) {
    k = l.k;
    b = l.b;
    start = l.start;
    end = l.end;
  }
  float getStart() const {
    return start;
  }
  float getEnd() const {
    return end;
  }
  double getK() const {
    return k;
  }
  double getB() const {
    return b;
  }
};

struct mycmp {
  bool operator() (Line l1, Line l2) const {
    if (compare(l1.getK(), l2.getK()) == 0) {
      if (compare(l1.getB(), l2.getB()) == 0) {
	return compare(l1.getStart(), l2.getStart()) < 0;
      }
      return compare(l1.getB(),l2.getB()) < 0;
    }
    return compare(l1.getK(), l2.getK()) < 0;
  }
} cmp;

int main(void) {
  int n;
  cin >> n;
  while (n != 0) {
    vector<Line> lines;
    int i, num;
    double x1, y1, x2, y2;
    double maxend;
    for (i = 0; i < n; ++i) {
      cin >> x1 >> y1 >> x2 >> y2;
      if (compare(x1, x2) > 0) {
	swap(x1, x2);
	swap(y1, y2);
      }
      else if (compare(x1, x2) == 0){
	if (compare(y1, y2) > 0)
	  swap(y1, y2);
      }
      lines.push_back(Line(x1, y1, x2, y2));
    }
    sort(lines.begin(), lines.end(), cmp);
    num = lines.size();
    maxend = lines.front().getEnd();
    vector<Line>::iterator it1, it2;
    for (it1 = lines.begin(), it2 = it1, ++it2; it2 != lines.end(); ++it2, ++it1) {
      if (compare((*it1).getK(), (*it2).getK()) == 0 && compare((*it1).getB(), (*it2).getB()) == 0) {
	if ((*it2).getStart() <= maxend)
	  --num;
        if (maxend < (*it2).getEnd())
	  maxend = (*it2).getEnd();
      }
      else
        maxend = (*it2).getEnd();
    }
    cout << num << endl;
    cin >> n;
  }
  return 0;
}

参考资料

http://blog.csdn.net/xiehaoyun2012/article/details/8438257

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值