题意:铁人三项赛,给定每个选手游泳,自行车,赛跑三个阶段的平均速度,不知道每段比赛的路程,询问当前这个选手能否胜利。
思路:把题意转化为一个不等式,设比赛长度是1,如果i要战胜j,x、y分别是第一阶段和第二阶段的比赛长度: (x / ui + y / vi + (1-x-y) / wi) < (x / uj + y / vj + (1-x-y) / wj) 可以转化为Ax + By + C > 0的形式,也就可以用半平面交来解决,对于每个i都有其他n-1个j的半平面和x>0, y>0, (1-x-y)>0这三个半平面,如果这些半平面(n+2)都有交集,说明i有可能打败其他选手,否则不可能。
此题值得注意的是精度问题,选P点时(L上的一点),如果默认P=Point(-c/a,0),能过,但是只是P = Point(0, -c/b),就不行了。计算几何一点要注意精度问题!!!
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<memory.h> 7 #include<cstdlib> 8 #include<vector> 9 #define clc(a,b) memset(a,b,sizeof(a)) 10 #define LL long long int 11 #define up(i,x,y) for(i=x;i<=y;i++) 12 #define w(a) while(a) 13 const double inf=0x3f3f3f3f; 14 const int N = 4010; 15 const double eps = 5*1e-13; 16 const double PI = acos(-1.0); 17 using namespace std; 18 19 struct Point 20 { 21 double x, y; 22 Point(double x=0, double y=0):x(x),y(y) { } 23 }; 24 25 typedef Point Vector; 26 27 Vector operator + (const Vector& A, const Vector& B) 28 { 29 return Vector(A.x+B.x, A.y+B.y); 30 } 31 Vector operator - (const Point& A, const Point& B) 32 { 33 return Vector(A.x-B.x, A.y-B.y); 34 } 35 Vector operator * (const Vector& A, double p) 36 { 37 return Vector(A.x*p, A.y*p); 38 } 39 double Dot(const Vector& A, const Vector& B) 40 { 41 return A.x*B.x + A.y*B.y; 42 } 43 double Cross(const Vector& A, const Vector& B) 44 { 45 return A.x*B.y - A.y*B.x; 46 } 47 double Length(const Vector& A) 48 { 49 return sqrt(Dot(A, A)); 50 } 51 Vector Normal(const Vector& A) 52 { 53 double L = Length(A); 54 return Vector(-A.y/L, A.x/L); 55 } 56 57 double PolygonArea(vector<Point> p) 58 { 59 int n = p.size(); 60 double area = 0; 61 for(int i = 1; i < n-1; i++) 62 area += Cross(p[i]-p[0], p[i+1]-p[0]); 63 return area/2; 64 } 65 66 // 有向直线。它的左边就是对应的半平面 67 struct Line 68 { 69 Point P; // 直线上任意一点 70 Vector v; // 方向向量 71 double ang; // 极角,即从x正半轴旋转到向量v所需要的角(弧度) 72 Line() {} 73 Line(Point P, Vector v):P(P),v(v) 74 { 75 ang = atan2(v.y, v.x); 76 } 77 bool operator < (const Line& L) const 78 { 79 return ang < L.ang; 80 } 81 }; 82 83 // 点p在有向直线L的左边(线上不算) 84 bool OnLeft(const Line& L, const Point& p) 85 { 86 return Cross(L.v, p-L.P) > 0; 87 } 88 89 // 二直线交点,假定交点惟一存在 90 Point GetLineIntersection(const Line& a, const Line& b) 91 { 92 Vector u = a.P-b.P; 93 double t = Cross(b.v, u) / Cross(a.v, b.v); 94 return a.P+a.v*t; 95 } 96 97 const double INF = 1e8; 98 99 // 半平面交主过程 100 vector<Point> HalfplaneIntersection(vector<Line> L) 101 { 102 int n = L.size(); 103 sort(L.begin(), L.end()); // 按极角排序 104 105 int first, last; // 双端队列的第一个元素和最后一个元素的下标 106 vector<Point> p(n); // p[i]为q[i]和q[i+1]的交点 107 vector<Line> q(n); // 双端队列 108 vector<Point> ans; // 结果 109 110 q[first=last=0] = L[0]; // 双端队列初始化为只有一个半平面L[0] 111 for(int i = 1; i < n; i++) 112 { 113 while(first < last && !OnLeft(L[i], p[last-1])) last--; 114 while(first < last && !OnLeft(L[i], p[first])) first++; 115 q[++last] = L[i]; 116 if(fabs(Cross(q[last].v, q[last-1].v)) < eps) // 两向量平行且同向,取内侧的一个 117 { 118 last--; 119 if(OnLeft(q[last], L[i].P)) q[last] = L[i]; 120 } 121 if(first < last) p[last-1] = GetLineIntersection(q[last-1], q[last]); 122 } 123 while(first < last && !OnLeft(q[first], p[last-1])) last--; // 删除无用平面 124 if(last - first <= 1) return ans; // 空集 125 p[last] = GetLineIntersection(q[last], q[first]); // 计算首尾两个半平面的交点 126 127 // 从deque复制到输出中 128 for(int i = first; i <= last; i++) ans.push_back(p[i]); 129 return ans; 130 } 131 132 const int maxn = 100 + 10; 133 int V[maxn], U[maxn], W[maxn]; 134 int main() 135 { 136 int n; 137 while(scanf("%d", &n) == 1 && n) 138 { 139 for(int i = 0; i < n; i++) scanf("%d%d%d", &V[i], &U[i], &W[i]); 140 for(int i = 0; i < n; i++) 141 { 142 int ok = 1; 143 double k = 10000; 144 vector<Line> L; 145 for(int j = 0; j < n; j++) if(i != j) 146 { 147 if(V[i] <= V[j] && U[i] <= U[j] && W[i] <= W[j]) 148 { 149 ok = 0; 150 break; 151 } 152 if(V[i] >= V[j] && U[i] >= U[j] && W[i] >= W[j]) continue; 153 // x/V[i]+y/U[i]+(1-x-y)/W[i] < x/V[j]+y/U[j]+(1-x-y)/W[j] 154 // ax+by+c>0 155 double a = (k/V[j]-k/W[j]) - (k/V[i]-k/W[i]); 156 double b = (k/U[j]-k/W[j]) - (k/U[i]-k/W[i]); 157 double c = k/W[j] - k/W[i]; 158 Point P; 159 Vector v(b, -a); 160 if(fabs(a) > fabs(b)) 161 P = Point(-c/a, 0); 162 else 163 P = Point(0, -c/b); 164 L.push_back(Line(P, v)); 165 } 166 if(ok) 167 { 168 // x>0, y>0, x+y<1 ==> -x-y+1>0 169 L.push_back(Line(Point(0, 0), Vector(0, -1))); 170 L.push_back(Line(Point(0, 0), Vector(1, 0))); 171 L.push_back(Line(Point(0, 1), Vector(-1, 1))); 172 vector<Point> poly = HalfplaneIntersection(L); 173 if(poly.empty()) ok = 0; 174 } 175 if(ok) printf("Yes\n"); 176 else printf("No\n"); 177 } 178 } 179 return 0; 180 }
时间: 2024-10-20 17:09:57