题目描述:http://poj.org/problem?id=1755
解题思路:
假设一个队员的各项速度为(v1,v2,v3),每项的距离为(x, y, z),那么她完成比赛的时间t = x/v1 + y/v2 + z/v3。
一名选手可以获得第一,当且仅当对于其他任意一名选手(v1', v2', v3'), t<t'有解。
即 x/v1+y/v2+z/v3 < x/v1'+y/v2'+z/v3' -> (1/v1-1/v1') x + (1/v2-1/v2') y + (1/v3-1/v3') z < 0 有解。
这个方程确定了一个三维半空间,因为x,y,z>0,所以左边除以z可以降到二维,就成为了一个半平面。
对于第i个选手,其余n-1个选手所确定的半平面如果有解则证明这名选手可以获得第一。
其他还有一些需要注意的地方。
1. 已知两点,求这两点确定的直线与给定方程的直线的交点。假设交点(x,y),因为(x1,y1)(x,y)(x2,y2)在同一直线上,利用叉乘可以列出一个方程。又因为(x,y)在给定直线方程上,联立可以解出(x, y)。
2. 看了discuss才知道eps要开到1e-16,不然一直WA..
3. 当两名队员的v1 v2 v3相等时,他们都不可能成为唯一的第一名,这一点需要特判。
<span style="font-family:Microsoft YaHei;font-size:14px;">/*
* 2014.11.22
* Problem: 1755
* Memory: 204K Time: 0MS
* Language: C++ Result: Accepted
*
*/
#include "iostream"
#include "cmath"
#define EPS 1e-16 //!
#define MAXN 107
#define INF 1e10
#define zero(a) (fabs(a)<EPS)
struct Point {
double x, y;
Point(){}
Point(double _x, double _y):x(_x),y(_y){}
};
struct Equation {
double a, b, c;
Equation(){}
Equation(double _a, double _b, double _c):a(_a),b(_b),c(_c){}
}a[MAXN];
int n;
void init() {
scanf("%d", &n);
double v1, v2, v3;
for (int i=1; i<=n; i++) {
scanf("%lf %lf %lf", &v1, &v2, &v3);
a[i].a = v1; a[i].b = v2; a[i].c = v3;
}
}
double cross(Point a, Point b, Point c) {
double x1 = b.x-a.x, y1 = b.y-a.y, x2 = c.x-a.x, y2 = c.y-a.y;
return x1*y2 - x2*y1;
}
double area(Point p[], int pn) {
double a = 0;
for (int i=2; i<pn; i++) a += cross(p[1], p[i], p[i+1]);
return a;
}
Point intersect(Point p1, Point p2, double a, double b, double c) {
double d = p2.y-p1.y, e = p1.x-p2.x, f = p1.x*p2.y - p2.x*p1.y;
c = -c;
return Point((c*e-b*f)/(a*e-b*d), (c*d-a*f)/(b*d-a*e));
}
bool cut(Point c[], int &cn, double A, double B, double C) { // &cn!!
Point t[MAXN];
int tn = 0;
for (int i=1; i<=cn; i++) {
if (A*c[i].x+B*c[i].y+C<EPS) t[++tn] = c[i];
else {
if (A*c[i-1].x+B*c[i-1].y+C<-EPS) t[++tn] = intersect(c[i], c[i-1], A, B, C);
if (A*c[i+1].x+B*c[i+1].y+C<-EPS) t[++tn] = intersect(c[i], c[i+1], A, B, C);
}
}
if (zero(area(t, tn))) return false;
for (int i=1; i<=tn; i++) c[i] = t[i];
c[0] = c[cn=tn]; c[cn+1] = c[1];
return true;
}
bool planeIntersect(Equation e[], int n) {
Point c[MAXN];
int cn;
c[1] = Point(EPS, EPS); c[2] = Point(EPS, INF); c[3] = Point(INF, INF); c[4] = Point(INF, EPS);
cn = 4; c[0] = c[cn]; c[cn+1] = c[1];
for (int i=1; i<=n; i++) {
if (zero(e[i].a)&&zero(e[i].b)&&zero(e[i].c)) return false;
if (!cut(c, cn, e[i].a, e[i].b, e[i].c)) return false;
}
return true;
}
int main() {
init();
Equation ln[MAXN];
int lnn;
for (int i=1; i<=n; i++) {
lnn = 0;
for (int j=1; j<=n; j++)
if (i!=j) ln[++lnn] = Equation((a[j].a-a[i].a)/(a[i].a*a[j].a),
(a[j].b-a[i].b)/(a[i].b*a[j].b),
(a[j].c-a[i].c)/(a[i].c*a[j].c));
if (planeIntersect(ln, lnn)) {
printf("Yes\n");
} else {
printf("No\n");
}
}
return 0;
}
</span>