UVALive 4127

来源:互联网 发布:怎样注册淘宝号 编辑:程序博客网 时间:2024/06/08 11:35

Link:click here
The question:给出n座山的高和宽,山视为等腰三角形,从上往下看,求山的轮廓的长度,山之间的空白不算。
Solution:用竖线在山与山的交点和顶点处,把所有山分成一段一段的的线段,统计竖线内每段线段的长度,累加即可。先把所有端点的横坐标放入数组X里, 然后对线段两两求交,把交点的横坐标也放入数组X里,然后排序去重。求出每条线段与竖线的交点的y坐标的最大值,因为竖线可能与多条线段相交,但只有最 上面的点是可见的。
Conclusion:判断直线相交改为判断直线不平行会简化很多,同时用到了离散化的思想
Code:

#include <bits/stdc++.h>using namespace std;const double eps = 1e-7;typedef struct Point{    double x, y;    Point(double x = 0.0, double y = 0.0): x(x), y(y) {}} Vector;struct Line{    Point a, b;    Line() {}    Line(Point a, Point b): a(a), b(b) {}} L[5000];Vector operator + (Vector A, Vector B){    return Vector(A.x + B.x, A.y + B.y);}Vector operator - (Vector A, Vector B){    return Vector(A.x - B.x, A.y - B.y);}Vector operator * (Vector A, double t){    return Vector(A.x * t, A.y * t);}Vector operator / (Vector A, double t){    return Vector(A.x / t, A.y / t);}int dcmp(double x){    if (fabs(x) < eps)        return 0;    return x < 0.0 ? -1 : 1;}double Dot(Vector A, Vector B){    return A.x * B.x + A.y * B.y;}double Cross(Vector A, Vector B){    return A.x * B.y - A.y * B.x;}bool segment(Point a1, Point a2, Point b1, Point b2){    return dcmp(Cross(a1 - a2, b1 - b2)) != 0;}Point get(Point p, Vector v, Point q, Vector w){    Vector u = p - q;    double t = Cross(w, u) / Cross(v, w);    return p + v * t;}bool onsegment(Point p, Point a1, Point a2){    return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) <= 0;}int dex = 0, fix = 0;double H(double x)//求横坐标为x时,对应的线段上的y坐标的最大值{    double ans = 0.0;    for (int i = 0; i < dex; i++)    {        if (segment(Point(x, -1000.0), Point(x, 1000.0), L[i].a, L[i].b))        {            Point tmp = get(Point(x, -1000.0), Vector(0.0, 2000), L[i].a, Vector(L[i].b - L[i].a));            if (onsegment(tmp, L[i].a, L[i].b))            {                ans = max(ans, tmp.y);            }        }    }    return ans;}double X[500000];int main(){    int n, cas = 1;    while (scanf("%d", &n), n)    {        dex = fix = 0;        for (int i = 0; i < n; i++)        {            double x, h, b;            scanf("%lf%lf%lf", &x, &h, &b);            L[dex++] = Line(Point(x - 0.5 * b, 0.0), Point(x, h));            L[dex++] = Line(Point(x, h), Point(x + 0.5 * b, 0.0));            X[fix++] = x - 0.5 * b;            X[fix++] = x;            X[fix++] = x + 0.5 * b;        }        for (int i = 0; i < dex; i++)//求山与山与上的交点的横坐标        {            for (int j = i + 1; j < dex; j++)            {                if (segment(L[i].a, L[i].b, L[j].a, L[j].b))//如果相交                {                    Point tmp = get(L[i].a, L[i].b - L[i].a, L[j].a, L[j].b - L[j].a);//求交点                    if (onsegment(tmp, L[i].a, L[i].b))//交点在线段上                    {                        X[fix++] = tmp.x;                    }                }            }        }        sort(X, X + fix);//排序        fix = unique(X, X + fix) - X;//去重        double preh = H(X[0]);        double ans = 0.0;        for (int i = 1; i < fix; i++)//求所有竖线区间内的线段和        {            double nowh = H(X[i]);            double disx = fabs(X[i] - X[i - 1]);            double disy = fabs(nowh - preh);            if (dcmp(preh) || dcmp(nowh))//判断是不是同一个点            {                ans += sqrt(disx * disx + disy * disy);            }            preh = nowh;        }        printf("Case %d: %.0f\n\n", cas++, ans);    }    return 0;}
0 0
原创粉丝点击