程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU 4637 Rain on your Fat brother 線段與半圓和線段交 簡單題

HDU 4637 Rain on your Fat brother 線段與半圓和線段交 簡單題

編輯:C++入門知識

題意:

應該不難讀懂。

 


做法:

我們可以把雨滴看做靜止不動,然後maze(這題的那個人)就是往左上方運動就可以了,計算出maze能跑到的最遠的點,然後就是求起點和終點所構成的線段與每個雨滴交的時間,注意題目說每個雨滴可能會相交,所以我們對於每個雨滴算出相交的區間,然後對這些區間進行合並並且計算答案。

 


注意點:

1.maze有可能一開始就在雨滴裡面。

2.還有maze穿了一部分的雨滴就被追上了。 (竟然沒有這種數據)

3.兩線段共線的情況,就是三角形右邊的那條邊 與 maze的線段共線, 這種情況之下也要細分,但我沒判這種情況也AC了,說明沒有這種數據,但考慮問題時我們需要把它考慮進去。 (竟然沒有這種數據)

 


知道以上注意點AC應該不遠了,畢竟不是什麼難題,我的代碼沒有寫第三種情況。

 


 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define pii pair <double, double>
#define mp make_pair
#define pb push_back
#define X first
#define Y second
const double eps = 1e-8;
int dcmp(double x) {
    if (fabs(x) < eps)
        return 0;
    return x > eps ? 1 : -1;
}
struct point {
    double x, y;
    point() {

    }
    point(double x, double y) :
            x(x), y(y) {
    }
    double operator *(const point &t) const {
        return x * t.x + y * t.y;
    }
    point operator -(const point &t) const {
        return point(x - t.x, y - t.y);
    }
    point operator +(const point &t) const {
        return point(x + t.x, y + t.y);
    }
    point operator *(const double &t) const {       //    注意是 點乘
        return point(t * x, t * y);
    }
} s, e;

double v1, v2, v, t, x, T;
double ans;
int n;
inline double F(double x) {
    return x * x;
}
double cross(const point &o, const point &a, const point &b) {
    return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}
double dis(const point &a, const point &b) {
    return sqrt(F(a.x - b.x) + F(a.y - b.y));
}

bool segSegIntersect(const point &a, const point &b, const point &l, const point &r) { 	//兩線段相交(不考慮共線)
    return cross(a, b, l) * cross(a, b, r) < eps
            && cross(l, r, a) * cross(l, r, b) < eps;
}

double intersect(const point &a, const point &b, const point &l, const point &r) {  // 兩直線求交點的x
    double ret = a.x;
    double t = ((a.x - l.x) * (l.y - r.y) - (a.y - l.y) * (l.x - r.x))
            / ((a.x - b.x) * (l.y - r.y) - (a.y - b.y) * (l.x - r.x));
    return ret + (b.x - a.x) * t;
}

vector<double> vec; //記錄與雨滴的交點
vector<pii> res;   //記錄被雨滴打到的每個時間段

struct rain {
    point o, a, b, c;
    double r, h;
    /*			雨滴三角形的三個點標號
     * 				 c
     * 				/_\
     * 			       a   b
     */
    void in() {
        scanf("%lf%lf%lf%lf", &o.x, &o.y, &r, &h);
        a = o, b = o, c = o;
        a.x -= r;
        b.x += r;
        c.y += h;
    }
    bool inside(const point &p) {  	//點是否在雨滴裡面(包括邊界)
        return (dis(o, p) - eps < r && p.y - eps < o.y)
                || (cross(c, a, p) > -eps && cross(c, b, p) < eps
                        && p.y > o.y + eps);
    }

    void intersectC() {		//與雨滴的半圓 交 求交點
        point b = s, d = e - s;
        double A = d * d;
        double B = (b - o) * d * 2;
        double C = (b - o) * (b - o) - r * r;
        double dlt = B * B - 4 * A * C;
        if (dlt < -eps) return;

        if (dlt < eps) dlt = 0;		//消除dlt負數零的情況
        else dlt = sqrt(dlt);

        double t = (-B - dlt) / (2 * A);
        point tp = b + d * t;
        if (tp.x - eps < s.x && tp.x + eps > e.x && tp.y - eps < o.y)	//因為是半圓,注意把沒用的點判掉
            vec.pb(tp.x);

        t = (-B + dlt) / (2 * A);
        tp = b + d * t;
        if (tp.x - eps < s.x && tp.x + eps > e.x && tp.y - eps < o.y)
            vec.pb(tp.x);

    }

    void intersectT() { //與雨滴的三角形 交 求交點 (水平的線段不算在其中)
        double x;
        if (segSegIntersect(a, c, s, e)) {
            x = intersect(a, c, s, e);
            if (x - eps > e.x && x + eps < s.x)
                vec.pb(x);
        }
        if (segSegIntersect(c, b, s, e)) {
            x = intersect(c, b, s, e);
            if (x - eps > e.x && x + eps < s.x)
                vec.pb(x);
        }
    }

    void gao() {

        vec.clear();
        intersectC();
        intersectT();
        if (inside(s)) vec.pb(s.x);
        if (inside(e)) vec.pb(e.x);
        sort(vec.begin(), vec.end());
        int cnt = unique(vec.begin(), vec.end()) - vec.begin();
        if (cnt >= 2)			//取最大和最小的兩個交點  就是被雨滴打到的時間段  的 兩端點
            res.pb(mp(vec[0], vec[cnt - 1]));
    }
} p;

int main() {
    int i, j, cas;
    scanf("%d", &cas);
    for (int ca = 1; ca <= cas; ca++) {
        scanf("%lf%lf%lf%lf%lf%d", &v1, &v2, &v, &t, &x, &n);
        T = v1 * t / (v2 - v1) + t;
        s.x = x;
        s.y = 0;
        e.x = x - v1 * T;
        e.y = v * T;
        ans = 0;
        res.clear();
        for (i = 0; i < n; i++) {
            p.in();
            p.gao();
        }

        //對每個時間段去重後計算答案
        sort(res.begin(), res.end());

        double r = e.x;
        int SZ = res.size();
        for (i = 0; i < SZ; i++) {
            if (res[i].X - eps < r && r - eps < res[i].Y) {
                ans += res[i].Y - r;
                r = res[i].Y;
            }
            else if (r - eps < res[i].X) {
                ans += res[i].Y - res[i].X;
                r = res[i].Y;
            }

        }
        printf("Case %d: %.4f\n", ca, ans / v1);
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved