ZOJ1886/POJ2540 Hotter Colder(半平面交)

來源:互聯網
上載者:User

題意是,有一個二維(0,0)到(10,10)的地區,一個人從(0,0)開始一次拜訪地區內的點,去找一樣東西(就在這個地區內),每次他到達一個新的點後,都會有一句話,來告訴你是離那個東西更近了(Hotter),還是更遠了(Colder),或者距離不變(Same),然後讓你算出,這時那個東西可能處在的位置的地區的面積

明顯的半平面交,每次取當前點和下一個點的中垂線向量加入多邊形邊集(當然,必須注意方向,根據距離的增加或者減小可以判斷),半平面交的面積就好了

代碼:

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>using namespace std;const double eps = 1e-8;const double pi = acos(-1.0);const int N = 60;const double maxl = 10;struct cpoint {//C++建構函式,預設預設值為(0,0)    double x, y;    cpoint(double xx = 0, double yy = 0): x(xx), y(yy) {};};int dcmp(double x) {//判斷參數的符號,負數返回-1,0返回0,正數返回1    if (x < -eps) return -1; else return x > eps;}double cross(cpoint p0, cpoint p1, cpoint p2) { // p0p1 與 p0p2 叉積    return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);}bool EqualPoint(cpoint a, cpoint b) {//兩點相等    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;}struct cvector {//向量    cpoint s, e;    double ang, d;};//atan (double x)弧度表示的反正切//atan2(double x,double y)弧度表示的反正切,相當於atan(x/y)void setline(double x1, double y1, double x2, double y2, cvector &v) {    v.s.x = x1; v.s.y = y1;    v.e.x = x2; v.e.y = y2;    v.ang = atan2(y2 - y1, x2 - x1);//這裡的 d 代表向量(直線)和座標軸的截距,正數表示 原點 在該向量的左邊//(這道題要求左半平面交),負號則表示 原點 在右邊    if (dcmp(x1 - x2))          // x1 > x2v.d = (x1 * y2 - x2 * y1) / fabs(x1 - x2);    else v.d = (x1 * y2 - x2 * y1) / fabs(y1 - y2);}//判向量平行bool parallel(const cvector &a, const cvector &b) {    double u = (a.e.x - a.s.x) * (b.e.y - b.s.y) - (a.e.y - a.s.y) * (b.e.x - b.s.x);    return dcmp(u) == 0;}//求兩向量(直線)交點 (兩向量不能平行或重合)cpoint CrossPoint(const cvector &a, const cvector &b) {    cpoint res;    double u = cross(a.s, a.e, b.s), v = cross(a.e, a.s, b.e);    res.x = (b.s.x * v + b.e.x * u) / (u + v);    res.y = (b.s.y * v + b.e.y * u) / (u + v);    return res;}//半平面交排序函數[優先順序: 1.極角 2.前面的直線在後面的左邊]static bool VecCmp(const cvector &l, const cvector &r) {    if (dcmp(l.ang - r.ang)) return l.ang < r.ang;    return l.d < r.d;}cvector deq[N]; //用於計算的雙端隊列void HalfPanelCross(cvector vec[], int n, cpoint cp[], int &m) {    int i, tn; m = 0;    sort(vec, vec + n, VecCmp);    for(i = tn = 1; i < n; ++i) //平面在向量左邊的篩選,方向相同的篩去,相反的不能篩去        if(dcmp(vec[i].ang - vec[i - 1].ang) != 0)            vec[tn++] = vec[i];n = tn;int bot = 0, top = 1;deq[0] = vec[0];deq[1] = vec[1]; // vec[]大小不可小於2for (i = 2; i < tn; ++i) {if (parallel(deq[top], deq[top - 1]) || parallel(deq[bot], deq[bot + 1]) ) return ;while ( bot < top && dcmp( cross(vec[i].s, vec[i].e, CrossPoint(deq[top], deq[top - 1])) ) < 0 ) top--;while ( bot < top && dcmp( cross(vec[i].s, vec[i].e, CrossPoint(deq[bot], deq[bot + 1])) ) < 0 ) bot++;deq[++top] = vec[i];}while ( bot < top && dcmp( cross(deq[bot].s, deq[bot].e, CrossPoint(deq[top], deq[top - 1])) ) < 0 ) top--;while ( bot < top && dcmp( cross(deq[top].s, deq[top].e, CrossPoint(deq[bot], deq[bot + 1])) ) < 0 ) bot++;if (top <= bot + 1) return ; // 兩條或兩條以下的直線,面積無窮大for (i = bot; i < top; i ++)cp[m++] = CrossPoint(deq[i], deq[i + 1]);if (bot < top + 1)cp[m++] = CrossPoint(deq[bot], deq[top]);m = unique(cp, cp + m, EqualPoint) - cp;}double PolygonArea(cpoint p[], int n) {    if (n < 3) return 0;    double s = p[0].y * (p[n - 1].x - p[1].x);    for (int i = 1; i < n; ++i)        s += p[i].y * (p[i - 1].x - p[(i + 1) % n].x);    return fabs(s / 2); // 順時針方向s為負}//向量的旋轉 //底邊線段ab 繞a逆時針旋轉角度A,b->b1,sinl是sinA的值。 cpoint Whirl(double cosl, double sinl, cpoint a, cpoint b){    b.x -= a.x; b.y -= a.y;    cpoint c;    c.x = b.x * cosl - b.y * sinl + a.x;    c.y = b.x * sinl + b.y * cosl + a.y;    return c;}int n, m;cvector v[N];cpoint cp[N],cur,next;void solve() {cpoint mid;char str[10];    scanf("%s",str);mid.x=(cur.x+next.x)/2; mid.y=(cur.y+next.y)/2;cpoint kp;    if(strcmp(str,"Colder")==0)kp=Whirl(0,1,mid,next);else if(strcmp(str,"Hotter")==0)kp=Whirl(0,-1,mid,next);cur=next;setline(mid.x,mid.y,kp.x,kp.y,v[n++]);    HalfPanelCross(v, n, cp, m);    if (m < 3) printf("0.00\n");    else printf("%.2lf\n", PolygonArea(cp, m));}int main() {cur.x = cur.y = 0.0;setline(0, 0, maxl, 0, v[0]);//v[0] ~ v[3] 是點集的外包矩陣    setline(maxl, 0, maxl, maxl, v[1]);    setline(maxl, maxl, 0, maxl, v[2]);    setline(0, maxl, 0, 0, v[3]);    n = 4;    while (~scanf("%lf%lf",&next.x,&next.y)){        solve();    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.