【HDU 1687】Lucky Light(思维+计算几何)

传送门: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;
    }
}
原文地址:https://www.cnblogs.com/Torrance/p/5445616.html