现在的位置: 首页 > 综合 > 正文

POJ1755-半平面交判断不等式是否有解

2013年12月21日 ⁄ 综合 ⁄ 共 2543字 ⁄ 字号 评论关闭

题目:题目链接

 

题意:就是给你铁人三项,每个人在某一项中有确定的速度,裁判可以决定某一项比赛的路程为多少,问对于某个

人,是否存在一种安排能使他拿到第一,而且不能是并列。

 

分析:假设每一段路程的长度分别为x, y, z,那么对于一个选手的时间就是x/u1+y/v1+z/w1;如果一个人要胜过另外

一个人那么必须满足方程式x/u1 + y/v1 + z/w1 < x/u2 + y/v2 + z/w2;就是说第一个人完成比赛所用到的时间比第

二个人的少,那么这样的话,我们会有三个未知数,用z分别除以符号两端,会得到两个未知数x/z 和 y/z这样的话

把x/z当作一个整体,再把y/z当作一个整体。那么就是对于某一个u, v, w是不是满足所有的不等式,使得它所用到

的时间最少。这里神奇般的用到了半平面交(条件 x > 0 y > 0).那么初始化一个范围为(0, 0),(0, INF), (INF,

0), (INF, INF).然后通过两个人的参数,求出AX+BY+C>0,通过半平面交解决,最终判断面积是否为0。处理精度问

题的时候对于对于1/U1-1/U2,普通的处理是需要两次除法,精度严重受损,可以改成(U2-U1)/(U1*U2)。这样可以减

少误差:

 

代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <bitset>
#include <stack>
#include <ctime>
#include <list>
#define inf 0x7fffffff
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
#define eps 1e-8
#define zero(a) fabs(a) < eps
using namespace std;

#define maxn 2000
struct point
{
    double x, y;
}p[maxn], q[maxn], tp[maxn];

struct node
{
    double u, v, w;
}cugb[110];

double xmul(point p0, point p1, point p2)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x);
}

point jiao(point p1, point p2, double a, double b, double c)
{
    double u = fabs(a*p1.x + b*p1.y + c);
    double v = fabs(a*p2.x + b*p2.y + c);
    point t;
    t.x = (p1.x*v + p2.x*u)/(u+v);
    t.y = (p1.y*v + p2.y*u)/(u+v);
    return t;
}
double AREA(point p[], int n)
{
    double area = 0;
    for(int i = 2; i < n; ++i)
    area += xmul(p[1], p[i], p[i+1]);
    return -area/2.0;
}

void cut(double a, double b, double c, point p[], int &cnt)//用直线ax+by+c==0切割多边形
{
    int tmp = 0;
    for(int i = 1; i <= cnt; ++i)
    {
        if(a*p[i].x + b*p[i].y + c > eps)
        tp[++tmp] = p[i];
        else
        {
            if(a*p[i-1].x + b*p[i-1].y + c > eps)//判断这个点前后的两个点
            tp[++tmp] = jiao(p[i-1], p[i], a, b, c);
            if(a*p[i+1].x + b*p[i+1].y + c > eps)
            tp[++tmp] = jiao(p[i], p[i+1], a, b, c);
        }
    }
    for(int i = 1; i <= tmp; ++i)//更新切割后的多边形
    p[i] = tp[i];
    p[0] = p[tmp];
    p[tmp+1] = p[1];
    cnt = tmp;
}

int solve(int n, int idx)
{
    p[1].x = 0;
    p[1].y = 0;
    p[2].x = 0;
    p[2].y = inf;
    p[3].x = inf;
    p[3].y = inf;
    p[4].x = inf;
    p[4].y = 0;//初始化两个未知数的范围
    p[0] = p[4];
    p[5] = p[1];
    int cnt = 4;
    for(int i = 0; i < n; ++i)
    {
        if(i == idx)
        continue;
        double a, b, c;
        a = (cugb[idx].u - cugb[i].u)/(cugb[idx].u*cugb[i].u);//按照x/(z*u)
        b = (cugb[idx].v - cugb[i].v)/(cugb[idx].v*cugb[i].v);//+ y/(z*v)
        c = (cugb[idx].w - cugb[i].w)/(cugb[idx].w*cugb[i].w);//+ 1/w = 0
        if(a == 0 && b == 0 && c < eps)
        return 0;
        cut(a, b, c, p, cnt);
    }
    return !zero(AREA(p, cnt));
}
int main()
{
    int n;
    while(scanf("%d", &n) == 1)
    {
        for(int i = 0; i < n; ++i)
        scanf("%lf%lf%lf", &cugb[i].u, &cugb[i].v, &cugb[i].w);
        for(int i = 0; i < n; ++i)//判断每一个参赛者
        {
            if(solve(n, i))
            puts("Yes");
            else
            puts("No");
        }
    }
    return 0;
}

 

 

 

抱歉!评论已关闭.