Sicily.1004. I Conduit!

/*1004. I Conduit!
   题目大意:给出一堆线段,求出需要画出最少的直线就可覆盖全部线段
             即有一部分重叠的线段用一条直线代表即可。 
             
   思路:先对每条线段求出其斜率k和截距b(如果没有截距,则用无限大代表)
         然后记录每条线段的起始位置(如果无斜率则为y坐标的较小的那个,如果
         有斜率,则为x坐标较小的那个),结束位置则取较大的那个。
         然后把线段数组先按k,后按b,最后按起始位置start从小到大排序
         排好序后,保证了同一直线上的线段在同一个区域内。
         然后先取出第一条线段的结束位置maxEnd,然后依次往后遍历,发现k和b相等的,
         即说明是同一条直线,就比较该线段的其实位置start与maxEnd的大小,如果是
         start在maxEnd前面,说明重叠,需要画的线段数num--,然后更新maxEnd。
         如果发现不重叠,就更新maxEnd 
*/
#include<iostream>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define INF 1e+15
#define EPS 1e-7
int cmp(double x1, double x2){
   if(x1 - x2 < -EPS) 
      return -1;
   if(x1 - x2 > EPS)
      return 1;
   return 0;   
}

struct Line{
    double k;
    double b;
    double start, end;
    Line(){
    }
    Line(double x1, double y1, double x2, double y2 ){
       if(cmp(x1, x2) == 0){
         k = INF;
         b = x1;
         start = min(y1, y2);
         end = max(y1, y2);                  
       }
       
       else{
         k = (y1 - y2)/(x1 - x2);
         b = y1 - k * x1;
         start = min(x1, x2);
         end = max(x1, x2);   
       }         
    }
};

bool cmpLine(Line a, Line b){
     if(cmp(a.k, b.k) != 0)
        return cmp(a.k,b.k ) < 0;
     if(cmp(a.b, b.b) != 0)
        return cmp(a.b,b.b ) < 0;   
     return cmp(a.start, b.start) < 0;
      
}
int n;
Line line[10000];

int main()
{
    while(cin >> n && n!=0){
      
        for(int i=0; i<n; i++) {
           double startX , startY, endX, endY;
           cin >> startX >> startY >> endX >> endY;
           line[i] = Line(startX, startY, endX, endY);
        }
        
        sort(line, line+n, cmpLine);
        int num = n;
        double maxEnd = line[0].end;
        
        for(int i=1; i<n; i++){ 
           if(cmp(line[i].k, line[i-1].k) == 0 && cmp(line[i].b, line[i-1].b) == 0)
           {
              if(cmp(line[i].start, maxEnd)<= 0 )
                num--;
              maxEnd = max(maxEnd, line[i].end);                
           }
           else
              maxEnd = line[i].end;        
        }
        cout << num << endl;
    }   
    system("pause");
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值