线段合并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; } }