LA 2218 (半平面交) Triathlon

题意:

有n个选手,铁人三项有连续的三段,对于每段场地选手i分别以vi, ui 和 wi匀速通过。

对于每个选手,问能否通过调整每种赛道的长度使得他成为冠军(不能并列)。

分析:

粗一看,这不像一道计算几何的题目。

假设赛道总长度是1,第一段长x,第二段长y,第三段则是1-x-y

那么可以计算出每个选手完成比赛的时间Ti

对于选手i,若要成为冠军则有Ti < Tj (i ≠ j)

于是就有n-1个不等式,每个不等式都代表一个半平面。

在加上x>0, y>0, 1-x-y>0 这三个半平面一共有n+2个半平面。如果这些半平面交非空,则选手i可以成为冠军。

最终,还是转化成了半平面交的问题。

细节:

  • 对于半平面 ax+by+c > 0 所对应的向量(b, -a)是和系数的正负没有关系的,可以自己试验下。开始我纠结了好长时间
  • if(fabs(a) > fabs(b))    P = Point(-c/a, 0)
    else P = Point(0, -c/b);

    对于这段代码不是太清楚它的含义,因为不管怎样P都是在ax+by+c = 0 这条直线上的。我猜可能是减小浮点运算的误差吧?

  1 //#define LOCAL
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 using namespace std;
  8
  9 const double eps = 1e-6;
 10 const int maxn = 100 + 10;
 11 int v[maxn], u[maxn], w[maxn];
 12
 13 struct Point
 14 {
 15     double x, y;
 16     Point(double x=0, double y=0):x(x), y(y) {}
 17 };
 18 typedef Point Vector;
 19 Point operator + (Point a, Point b) { return Point(a.x+b.x, a.y+b.y); }
 20 Point operator - (Point a, Point b) { return Point(a.x-b.x, a.y-b.y); }
 21 Vector operator * (Vector a, double p) { return Vector(a.x*p, a.y*p); }
 22 Vector operator / (Vector a, double p) { return Vector(a.x/p, a.y/p); }
 23 bool operator < (const Point& a, const Point& b)
 24 { return a.x < b.x || (a.x == b.x && a.y < b.y); }
 25 bool operator == (const Point& a, const Point& b)
 26 { return a.x == b.x && a.y == b.y; }
 27 double Dot(const Vector& a, const Vector& b) { return a.x*b.x + a.y*b.y; }
 28 double Cross(const Vector& a, const Vector& b) { return a.x*b.y - a.y*b.x; }
 29 double Length(const Vector& a) { return sqrt(Dot(a, a)); }
 30 Vector Normal(const Vector& a)
 31 {
 32     double l = Length(a);
 33     return Vector(-a.y/l, a.x);
 34 }
 35
 36 double PolygonArea(const vector<Point>& p)
 37 {
 38     int n = p.size();
 39     double ans = 0.0;
 40     for(int i = 1; i < n-1; ++i)
 41         ans += Cross(p[i]-p[0], p[i+1]-p[0]);
 42     return ans/2;
 43 }
 44
 45 struct Line
 46 {
 47     Point P;
 48     Vector v;
 49     double ang;
 50     Line() {}
 51     Line(Point p, Vector v):P(p), v(v) { ang = atan2(v.y, v.x); }
 52     bool operator < (const Line& L) const
 53     {
 54         return ang < L.ang;
 55     }
 56 };
 57
 58 bool OnLeft(const Line& L, Point p)
 59 {
 60     return Cross(L.v, p-L.P) > 0;
 61 }
 62
 63 Point GetLineIntersevtion(const Line& a, const Line& b)
 64 {
 65     Vector u = a.P - b.P;
 66     double t = Cross(b.v, u) / Cross(a.v, b.v);
 67     return a.P + a.v*t;
 68 }
 69
 70 vector<Point> HalfplaneIntersection(vector<Line> L)
 71 {
 72     int n = L.size();
 73     sort(L.begin(), L.end());
 74
 75     int first, last;
 76     vector<Point> p(n);
 77     vector<Line> q(n);
 78     vector<Point> ans;
 79
 80     q[first=last=0] = L[0];
 81     for(int i = 1; i < n; ++i)
 82     {
 83         while(first < last && !OnLeft(L[i], p[last-1])) last--;
 84         while(first < last && !OnLeft(L[i], p[first])) first++;
 85         q[++last] = L[i];
 86         if(fabs(Cross(q[last].v, q[last-1].v)) < eps)
 87         {
 88             last--;
 89             if(OnLeft(q[last], L[i].P)) q[last] = L[i];
 90         }
 91         if(first < last) p[last-1] = GetLineIntersevtion(q[last-1], q[last]);
 92     }
 93     while(first < last && !OnLeft(q[first], p[last-1])) last--;
 94     if(last - first <= 1)    return ans;
 95     p[last] = GetLineIntersevtion(q[first], q[last]);
 96
 97     for(int i = first; i <= last; ++i)    ans.push_back(p[i]);
 98     return ans;
 99 }
100
101 int main(void)
102 {
103     #ifdef    LOCAL
104         freopen("2218in.txt", "r", stdin);
105     #endif
106
107     int n;
108     while(scanf("%d", &n) == 1 && n)
109     {
110         for(int i = 0; i < n; ++i) scanf("%d%d%d", &v[i], &u[i], &w[i]);
111         for(int i = 0; i < n; ++i)
112         {
113             int ok = 1;
114             double k = 10000;
115             vector<Line> L;
116             for(int j = 0; j < n; ++j) if(j != i)
117             {
118                 if(v[i]<=v[j] && u[i]<=u[j] && w[i]<=w[j]) { ok = 0; break; }
119                 if(v[i]>v[j] && u[i]>u[j] && w[i]>w[j]) continue;
120
121                 double a = (k/v[j]-k/v[i]+k/w[i]-k/w[j]);
122                 double b = (k/u[j]-k/u[i]+k/w[i]-k/w[j]);
123                 double c = k/w[j]-k/w[i];
124                 //L.push_back(Line(Point(0, -c/b), Vector(b, -a)));
125                 Point P;
126                 Vector V(b, -a);
127                 if(fabs(a) > fabs(b))    P = Point(-c/a, 0);
128                 else P = Point(0, -c/b);
129                 L.push_back(Line(P, V));
130             }
131             if(ok)
132             {
133                 L.push_back(Line(Point(0, 0), Vector(0, -1)));
134                 L.push_back(Line(Point(0, 0), Vector(1, 0)));
135                 L.push_back(Line(Point(0, 1), Vector(-1, 1)));
136                 vector<Point> Poly = HalfplaneIntersection(L);
137                 if(Poly.empty()) ok = 0;
138             }
139             if(ok) puts("Yes"); else puts("No");
140         }
141     }
142
143     return 0;
144 }

代码君

时间: 2024-12-24 10:40:18

LA 2218 (半平面交) Triathlon的相关文章

LA 3890 (半平面交) Most Distant Point from the Sea

题意: 给出一个凸n边形,求多边形内部一点使得该点到边的最小距离最大. 分析: 最小值最大可以用二分. 多边形每条边的左边是一个半平面,将这n个半平面向左移动距离x,则将这个凸多边形缩小了.如果这n个半平面交非空,则存在这样距离为x的点,反之则不存在. 半平面交的代码还没有完全理解. 和凸包类似,先对这些半平面进行极角排序.每次新加入的平面可能让队尾的平面变得“无用”,从而需要删除.由于极角序是环形的,所以也可能让队首元素变得“无用”.所以用双端队列来维护. 1 //#define LOCAL

poj 1755 Triathlon 半平面交求不等式的 是否为空集-------构造有向直线

题目来源: http://poj.org/problem?id=1755 分析: 设比赛总长度为 1, 其中游泳长度为x, 自行车长度为y, 赛跑长度为 1 - x - y, 则选手 i 打败 选手j (不能并列) 的条件是 x / v[i] + y / u[i] + (1 - x - y) / w[i]  <  x / v[j] + y / u[j] + (1 - x - y) / w[j] 整理为 a*x + b * y + c > 0 (直线向量为 (b , -a))   ,  为逆时针

简单几何(半平面交+二分) LA 3890 Most Distant Point from the Sea

题目传送门 题意:凸多边形的小岛在海里,问岛上的点到海最远的距离. 分析:训练指南P279,二分答案,然后整个多边形往内部收缩,如果半平面交非空,那么这些点构成半平面,存在满足的点. /************************************************ * Author :Running_Time * Created Time :2015/11/10 星期二 14:16:17 * File Name :LA_3890.cpp ********************

半平面交算法及简单应用

半平面:一条直线把二维平面分成两个平面. 半平面交:在二维几何平面上,给出若干个半平面,求它们的公共部分 半平面交的结果:1.凸多边形(后面会讲解到)2.无界,因为有可能若干半平面没有形成封闭3.直线,线段,点,空(属于特殊情况吧) 算法:1:根据上图可以知道,运用给出的多边形每相邻两点形成一条直线来切割原有多边形,如果多边形上的点i在有向直线的左边或者在直线上即保存起来,否则判断此点的前一个点i-1和后一个点i+1是否在此直线的左边或线上,在的话分别用点i和点i-1构成的直线与此时正在切割的直

POJ3525-Most Distant Point from the Sea(二分+半平面交)

Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3955   Accepted: 1847   Special Judge Description The main land of Japan called Honshu is an island surrounded by the sea. In such an island, it is natural t

bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...

题意:按y=Ax+B的形式给出n(<=50000)条直线,求从y值为无穷大的地方向下看能看到的直线编号 一看到题目就想到半平面交,以每条直线的上方为一个半平面,求半平面的交,交集中存在的直线就是能看到的直线 但是写出来之后发现样例都过不了... 对于样例,如果允许半平面在边界处重叠那么答案是1,2,3,如果不允许只有1.. 然后抱着试一试的心理交上去了,结果竟然直接AC了.. 后来看题解只需要考虑交点x坐标.. bzoj 1007 水平可见直线 半平面交稀里糊涂的过了...,布布扣,bubuko

POJ 2540 半平面交求可行区域面积

Hotter Colder Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2343   Accepted: 981 Description The children's game Hotter Colder is played as follows. Player A leaves the room while player B hides an object somewhere in the room. Player

poj 3525 Most Distant Point from the Sea 半平面交 + 二分

题目来源: http://poj.org/problem?id=3525 分析: 题意:给定一个凸多边形,求多边形中距离边界最远的点到边界的距离. 思路 : 每次将凸多边形每条边往里平移d,判断是否存在核:二分d即可. 多边形边上的点(x , y)往里平移d 后的 坐标: s , e  为向量的 起点和终点, len 为起点和终点的距离, h 为平移的距离 x' = x + dx y' = y + dy dx = ( s.y - e.y ) / len * h ,( 原理 是 利用 三角形的相似

UVALive 4992 Jungle Outpost(半平面交)

题意:给你n个塔(点)形成一个顺时针的凸包,敌人可以摧毁任何塔,摧毁后剩下的塔再组成凸包 在开始的凸包内选一点为主塔,保证敌人摧毁尽量多塔时主塔都还在现在的凸包内,求出最多摧毁的塔 题解:这题关键就是选的主塔在不同的地方,敌人就会摧毁不同的塔来让你的主塔暴露 因此这样想,找出敌人摧毁不同的塔后形成的所有不同的凸包,再求出所有凸包的交就好 具体就是,首先枚举摧毁塔的个数k,再把摧毁任意k个塔所形成的所有不同的凸包求一个交,如果为空就代表了摧毁k个塔一定可以保证无论主塔在哪儿都可以暴露(关键) 而所