ZOJ 2967——Colorful Rainbows
来源:互联网 发布:热处理工艺模拟软件 编辑:程序博客网 时间:2024/06/05 14:23
题意:有最多5000条线,要求出这些线里面能看到几条。能看到的线是指这条线在一个区间内比其他任何线的y坐标都要大。
思路:根据题目意思,可以看出要求的是在直角坐标系里面最“上面”的那几条线。能看到的线应该组成了一个两边高,中间低的凹的形状。知道了最后要求的大致形状以后,差不多可以想到按从左往右的方式来判断直线是否可见。
先不考虑平行直线,斜率最小的跟斜率最大的直线是一定可见的。从斜率最小的开始考虑。将直线按照斜率从小到大排序。第一条直线即斜率最小的直线,一定是可见的。加入第二条直线,这时因为只有两条直线,所以俩都可见。再加入第三条。第三条的斜率比第二个大,它不可能遮挡住第一条直线,因此它最多只能挡住第二条直线。如果第三条直线与第二条直线的交点的横坐标x1,比第二条直线与第一条直线交点的横坐标x2小或等于,那么第二条直线一定被遮住了(画画图就看出来了)。如果第二条直线没有被遮住,那么这时就可见三条直线。这时,第二条直线有两个交点,将横坐标小的记为p1,将横坐标大的记为p2。
往后每加入一条直线都如此。这样,每一条可见的直线都会记录两个坐标,代表这条直线可见的区间(第一条直线只有与第二条直线一个交点,可以将第一条直线与所有直线中交点最小的给求出来作为它的p1,这样就将第一条直线的处理一般化了)。新加入一条直线以后,如果它会遮挡住直线l,那么在前面判断可见的直线中,斜率比l大的全部都会被遮住。
在判断的过程中,可见的直线相当于一个栈,栈中元素斜率依次增加。每加入一条直线,在里面找不能被挡住的最后一个直线,这条直线以后的所有都看不到了。
我用了两种方法实现,一种是栈顶元素一个一个弹出,另一种是用二分找到最后一个能看到的直线。
代码:
#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;}
- ZOJ 2967——Colorful Rainbows
- ZOJ 2967Colorful Rainbows
- ZOJ 2967-C - Colorful Rainbows
- 【计算几何】ZOJ 2967 Colorful Rainbows
- zoj 2967 Colorful Rainbows (堆栈应用)
- zoj 2967 Colorful Rainbows求不被覆盖的直线数(贪心)
- 省赛Colorful Rainbows
- ZOJ2967-Colorful Rainbows
- Colorful Rainbows(计算几何)
- C - Colorful Rainbows 解题报告 (双向栈)
- zoj2967 Colorful Rainbows(凸包 排序 栈)
- C - Colorful Rainbows----(2015 summer training #4 (Qualifying))
- sdut2879——Colorful Cupcakes(枚举终点记忆化搜索)
- 山东省第五届ACM省赛题——Colorful Cupcakes(四维dp)
- 【HDU】5574 Colorful Tree【子树染色,询问子树颜色数——线段树+bit+lca+set】
- ZOJ——5013
- zoj july— 小记
- ZOJ—2610
- 使用Jquery--Jsp与servlet之间的数据交互
- 六大设计原则(一)单一职责原则、里氏替换原则
- Redis学习1_Redis快速入门
- clientHeight offsetHeight scrollHeight
- POJ 1346--King 【差分约束】
- ZOJ 2967——Colorful Rainbows
- Android中app卡顿原因分析(ios顺滑)
- hadoop之MapReduce调用R的一次失败的总结~(续四)
- Windows7设置系统自动开机输入密码
- iOS Sprite Kit教程之场景的设置
- Android-Toolbar 使用
- OpenGL版本
- HTTP协议学习笔记(一)
- 基于Web的在线考试系统