ZOJ 2967——Colorful Rainbows
2015-07-27 14:51
369 查看
题意:有最多5000条线,要求出这些线里面能看到几条。能看到的线是指这条线在一个区间内比其他任何线的y坐标都要大。
思路:根据题目意思,可以看出要求的是在直角坐标系里面最“上面”的那几条线。能看到的线应该组成了一个两边高,中间低的凹的形状。知道了最后要求的大致形状以后,差不多可以想到按从左往右的方式来判断直线是否可见。
先不考虑平行直线,斜率最小的跟斜率最大的直线是一定可见的。从斜率最小的开始考虑。将直线按照斜率从小到大排序。第一条直线即斜率最小的直线,一定是可见的。加入第二条直线,这时因为只有两条直线,所以俩都可见。再加入第三条。第三条的斜率比第二个大,它不可能遮挡住第一条直线,因此它最多只能挡住第二条直线。如果第三条直线与第二条直线的交点的横坐标x1,比第二条直线与第一条直线交点的横坐标x2小或等于,那么第二条直线一定被遮住了(画画图就看出来了)。如果第二条直线没有被遮住,那么这时就可见三条直线。这时,第二条直线有两个交点,将横坐标小的记为p1,将横坐标大的记为p2。
往后每加入一条直线都如此。这样,每一条可见的直线都会记录两个坐标,代表这条直线可见的区间(第一条直线只有与第二条直线一个交点,可以将第一条直线与所有直线中交点最小的给求出来作为它的p1,这样就将第一条直线的处理一般化了)。新加入一条直线以后,如果它会遮挡住直线l,那么在前面判断可见的直线中,斜率比l大的全部都会被遮住。
在判断的过程中,可见的直线相当于一个栈,栈中元素斜率依次增加。每加入一条直线,在里面找不能被挡住的最后一个直线,这条直线以后的所有都看不到了。
我用了两种方法实现,一种是栈顶元素一个一个弹出,另一种是用二分找到最后一个能看到的直线。
代码:
思路:根据题目意思,可以看出要求的是在直角坐标系里面最“上面”的那几条线。能看到的线应该组成了一个两边高,中间低的凹的形状。知道了最后要求的大致形状以后,差不多可以想到按从左往右的方式来判断直线是否可见。
先不考虑平行直线,斜率最小的跟斜率最大的直线是一定可见的。从斜率最小的开始考虑。将直线按照斜率从小到大排序。第一条直线即斜率最小的直线,一定是可见的。加入第二条直线,这时因为只有两条直线,所以俩都可见。再加入第三条。第三条的斜率比第二个大,它不可能遮挡住第一条直线,因此它最多只能挡住第二条直线。如果第三条直线与第二条直线的交点的横坐标x1,比第二条直线与第一条直线交点的横坐标x2小或等于,那么第二条直线一定被遮住了(画画图就看出来了)。如果第二条直线没有被遮住,那么这时就可见三条直线。这时,第二条直线有两个交点,将横坐标小的记为p1,将横坐标大的记为p2。
往后每加入一条直线都如此。这样,每一条可见的直线都会记录两个坐标,代表这条直线可见的区间(第一条直线只有与第二条直线一个交点,可以将第一条直线与所有直线中交点最小的给求出来作为它的p1,这样就将第一条直线的处理一般化了)。新加入一条直线以后,如果它会遮挡住直线l,那么在前面判断可见的直线中,斜率比l大的全部都会被遮住。
在判断的过程中,可见的直线相当于一个栈,栈中元素斜率依次增加。每加入一条直线,在里面找不能被挡住的最后一个直线,这条直线以后的所有都看不到了。
我用了两种方法实现,一种是栈顶元素一个一个弹出,另一种是用二分找到最后一个能看到的直线。
代码:
[code]#include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<cstdio> #include<map> #include<cmath> #include<assert.h> #include<iomanip> #include<assert.h> using namespace std; typedef long long ll; int dcmp(double x){ if(fabs(x)<1e-9)return 0; return x<0?-1:1; } struct Point{ double x,y; Point(double _x=0,double _y=0):x(_x),y(_y){} bool operator < (const Point &a) const { return x<a.x; } bool operator > (const Point &a) const { return x>a.x; } bool operator <= (const Point &a) const { return dcmp(x-a.x)<=0; } bool operator >= (const Point &a) const { return dcmp(x-a.x)>=0; } }; struct Line{ double a,b; Point p1; Point p2; bool operator < (const Line &l) const{ if(dcmp(a-l.a)!=0)return a<l.a; return b>l.b; } }line[5005]; Point crosspoint(Line l1,Line l2){ double x = (l2.b-l1.b)/(l1.a-l2.a); return Point(x,l1.a*x+l1.b); } int main() { // freopen("data.txt","r",stdin); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=0;i<n;++i){ scanf("%lf%lf",&line[i].a,&line[i].b); } sort(line,line+n); line[0].p1=crosspoint(line[1],line[0]); for(int i=1;i<n;++i){ Point c = crosspoint(line[0],line[i]); line[0].p1=min(line[0].p1,c); } line[0].p1 = Point(line[0].p1.x-1,(line[0].p1.x-1)*line[0].a+line[0].b);//第一条直线的预处理,给它的p1赋值。横坐标减一是为了防止所有点都与第一条直线相交于一点的情况。 int last=0; for(int i=1;i<n;++i){ if(dcmp(line[i].a-line[i-1].a)==0){ continue; } assert(last>=0); line[last].p2 = crosspoint(line[last],line[i]); if(line[last].p2<=line[last].p1){ last--; }//最后的可见的直线的p2都没有求,新加入直线的时候先把它求出来。 ///////////////////+++++++++++++++++++++++ // while(last>=0){ // Point cp = crosspoint(line[last],line[i]); // if(cp<=line[last].p1){ // last--; // } else { // line[i].p1 = cp; // line[last].p2 = cp;break; // } // } // line[++last]=line[i]; // continue; ////////////////////+++++++++++++++++++++++ int l=0; int r=last; while(l<=r){ int mid = (l+r)>>1; Point cp = crosspoint(line[i],line[mid]); if(line[mid].p1>line[mid].p2)swap(line[mid].p1,line[mid].p2); if(cp>line[mid].p1&&cp<=line[mid].p2){ l=r=mid;line[mid].p2=cp;line[i].p1=cp;last = mid;break; } else if(cp>line[mid].p2){ l=mid+1; } else if(cp<=line[mid].p1){ r=mid-1; } else assert(0); } line[last+1]=line[i]; last++; } printf("%d\n",last+1); } return 0; }
相关文章推荐
- 2.朴素贝叶斯Naive Bayes
- Repair U Disk logo unvisiable in task bar on windows XP
- ultraiso命令行使用
- 一个单元测试 学习 aysnc await
- ACboy needs your help again!(简单栈)
- 2015 Multi-University Training Contest 1 /hdu 5289 Assignment -树状数组
- HDOJ N!Again(第一周)
- Train Problem I(栈)
- LeeCode(Database)-Duplicate Emails
- main()函数参数的意义
- HDU 1532 基础EK Drainage Ditches
- Source Insight函数调用关系显示设置http://blog.csdn.net/duanbeibei/article/details/24395777
- singnal 13 was raised
- gdb基本调试(cp:http://blog.csdn.net/feixiaoxing/article/details/7199643)
- 在linux中使用vi 打开文件时,能显示行号吗?http://zhidao.baidu.com/link?url=km4N-VLhK1DtSUOexgWMiZ73tp7R91g2UhZ15eTZv4
- Ubuntu 中sendmail 的安装、配置与发送邮件的具体实现
- Fibonacci Again
- AirPlay、DLNA、Miracast三大无线技术介绍
- 中小企业TurboMail邮件系统建设方案指导
- linux 进程等待 wait 、 waitpid