SOJ 1004

1004. I Conduit!

Constraints

Time Limit: 3 secs, Memory Limit: 32 MB

Description

Irv Kenneth Diggit works for a company that excavates trenches, digs holes and generally tears up people's yards. Irv's job is to make sure that no underground pipe or cable is underneath where excavation is planned. He has several different maps, one for each utility company, showing where their conduits lie, and he needs to draw one large, consolidated map combining them all. One approach would be to simply draw each of the smaller maps one at a time onto the large map. However, this often wastes time, not to mention ink for the pen-plotter in the office, since in many cases portions of the conduits overlap with each other (albeit at different depths underground). What Irv wants is a way to determine the minimum number of line segments to draw given all the line segments from the separate maps.

Input

Input will consist of multiple input sets. Each set will start with a single line containing a positive integer n indicating the total number of line segments from all the smaller maps. Each of the next n lines will contain a description of one segment in the format x1 y1 x2 y2 where (x1,y1) are the coordinates of one endpoint and (x2,y2) are the coordinates of the other. Coordi- nate values are floating point values in the range 0... 1000 specified to at most two decimal places. The maximum number of line segments will be 10000 and all segments will have non-zero length. Following the last input set there will be a line containing a 0 indicating end of input; it should not be processed.

Output

For each input set, output on a single line the minimum number of line segments that need to be drawn on the larger, consolidated map.

Sample Input

3
1.0 10.0 3.0 14.0
0.0 0.0 20.0 20.0
10.0 28.0 2.0 12.0
2
0.0 0.0 1.0 1.0
1.0 1.0 2.15 2.15
2
0.0 0.0 1.0 1.0
1.0 1.0 2.15 2.16
0

Sample Output

2
1

2

此题最大的难点在于要想到排序,将输入的每条线段按斜率、截距、起点(优先级依次降低,即若斜率相等则按截距排)来排序,排序之后,将线段依次两两比较,若斜率截距相等,则可以判断它们共线,在比较后一条线段的起点是否小于等于前一条的终点(因为排序完成之后,后一条线段的起点必定大于等于前一条),若是则认为它们部分重合,则总图中线段数量减一(数量初始设为分图中线段总数)。

排序之后解决起来思路就非常清晰了,若不排序就按照输入数据的顺序来判断就非常复杂,可能后输入的线段会将之前两条或更多共线但不重合的线段连接起来,则还需要一个邻接矩阵或邻接链表来记录任意两个线段的连接情况,并实时更新。尝试这种解法后提交没有通过,总而言之还是排序再做好。

// Problem#: 1004
// Submission#: 4920778
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <algorithm>
#include<cmath>
using namespace std;
class line{//自定义“线段“数据类型,数据成员包括起始点,终点,斜率和截距 
    public:
        double start;
        double end;
        double slope;
        double intercept;
        line(double Start=0,double End=0,double Slope=0,double Intercept=0):start(Start),end(End),slope(Slope),intercept(Intercept){
        }
        
        
};
const int maxslope=99999;//当斜率不存在的时候,将其设为99999 
const double mininter=1e-6;//由于斜率和截距都是浮点数,所以当两个斜率之差小于一个极小值时就认为他们相等 
double getslope(double x1,double y1,double x2,double y2)//求斜率函数 
{
    if(x1==x2)
    return maxslope;
    else return (y2-y1)/(x2-x1);
}
double getintercept(double x1,double y1,double x2,double y2)//求截距函数 
{
    if(x1==x2)
    return x1;
    else 
    return (x2*y1-x1*y2)/(x2-x1);
}
bool compare(line A,line B)//因为下面需要对线段类型的对象进行排序,所以自定义了sort排序函数所需要的比较函数 
{
    if(fabs(A.slope-B.slope)>mininter)//先按斜率排序 从小到大 
    return A.slope<B.slope ;
    else if(fabs(A.intercept-B.intercept)>mininter)//斜率相同按截距 从小到大排序 
        return A.intercept <B.intercept;
    else return A.start<B.start;//截距相同按起始点从小到大排序 
}

int main()
{
    int n;//保存输入坐标数据的组数 
    line set[10000];//保存线段对象的数组,因为最多输入10000组,故大小直接设为10000 
    double x1,y1,x2,y2;
    while(cin>>n&&n)
    {
        int count=n;//count记录总图上的线段数,先假定无线段重合,故总图线段数量为n,后面再根据重合情况相应的调整 
        for(int i=0;i<n;++i)
        {
           cin>>x1>>y1>>x2>>y2;
           if(x1==x2)//用构造函数创建线段临时对象 line(start,end,slope,intercept) 
           set[i]=line(min(y1,y2),max(y1,y2),getslope(x1,y1,x2,y2),getintercept(x1,y1,x2,y2));//注意起止点的选取,若斜率不为0也不为无穷,起止点可以选x也可以选y,当斜率为0时,起止点只能选x,斜率正无穷时起止点只能选y 
           else
           set[i]=line(min(x1,x2),max(x1,x2),getslope(x1,y1,x2,y2),getintercept(x1,y1,x2,y2));
         
       }
       sort(set,set+n,compare);//进行排序 
       for(int i=1;i<n;++i)
       {
        if(fabs(set[i].slope-set[i-1].slope)<mininter&&fabs(set[i].intercept-set[i-1].intercept)<mininter&&set[i].start <=set[i-1].end )//当斜率和截距都相同且后一条线段的起点小于等于前一条的终点时,即可认为它们部分重合 
        {
            count--;
            set[i].end=max(set[i-1].end,set[i].end);//两条线段部分重合则形成了一条新线段,新线段终点为原两条线段中较大的那个 
           }
       }
       cout<<count<<endl; 
   }
   return 0;
}                                 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值