传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1687
题意:有一个光源,下面有很多放置的板子,问光线被板子分割之后在地上能产生多少块亮区(看题中的图就能看懂)。
分析:这个题的做法和省选第一天的C题很像,由于是求在地面上,也就是一条直线上的亮区,我们可以求出地面上被木板遮挡形成的暗区的左坐标和右坐标,然后合并区间就可以了。而求地面上的坐标,可以用相似三角形,若光源为(sx,sy),点为(x1,y1)和(x2,y2),则地面上的坐标为:sx-(sx-s1)*sy/(sy-y1)和sx-(sx-s2)*sy/(sy-y2),需要注意的是两个坐标中较小的为左,大的为右,最好不要根据输入的x1,y1,x2,y2的大小关系去判定哪个为左哪个为右,这样很容易落下某种特殊情况,因为这个点wa了6次才ac。
代码:
#include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<map> #include<algorithm> using namespace std; struct banzi{ double startn; double endn; }A[500]; bool comp(const banzi a ,const banzi b){ return a.startn<b.startn; } int main(){ int t; cin >> t; while(t--){ int n; cin >> n; int sx,sy; cin >> sx >> sy; for(int i=0;i<n;++i){ int x1,y1,x2,y2; cin >> x1 >> y1 >> x2 >> y2; double dian1=(double)sx-(sx-x1)*(sy)/(double)(sy-y1); double dian2=(double)sx-(sx-x2)*(sy)/(double)(sy-y2); A[i].startn=min(dian1,dian2); A[i].endn=max(dian1,dian2); } int light=(n>0?2:1); sort(A,A+n,comp); double endd=A[0].endn; for(int i=1;i<n;++i){ if(A[i].startn<=endd){ endd=max(endd,A[i].endn); } else{ ++light; endd=A[i].endn; } } cout << light << endl; } }