您的位置:首页 > 其它

Poj 1755 Triathlon (半平面交求可行域)

2012-12-28 23:50 465 查看
题目链接:http://poj.org/problem?id=1755

题意:有n个人参加三个赛段的比赛,三段总长一定,对于第i个人其在每一个赛段的速度分别为Vi,Ui,Wi,你作为一个裁判可以随意调整三个赛段的距离(都大于0),问是否能调整使得指定的选手获胜(不能并列)。

思路:设三个赛段的长度分别为a,b,c,则对第i人;用时分别为a/Vi,b/Ui,c/Wi,总时间Ti,获得冠军等价于对于任意第j人(j!=i),有Ti<Tj,即(1/Vi-1/Vj)*a+(1/Ui-1/Uj)*b+(1/Wi-1/Wj)*c<0,对不等式化简(令X=a/c,Y=b/c,A=1/Vi-1/Vj,B=1/Ui-1/Uj,C=1/Wi-1/Wj)得:A*X+B*Y+C<0。于是问题转化为半平面求交,先初始化一个大平面,然后用不等式表示的直线去切即可。

精度设为1e-16可过,虽然我尝试了把(1/Vi-1/Vj)写成(Vj-Vi)/(Vi*Vj),但貌似精度并没有明显提高……

学长的博文对平面的形状分析的更透彻:
http://www.cnblogs.com/jianglangcaijin/archive/2012/12/27/2836095.html
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

const double EPS=1e-16;
const int NUM=110;

int DB (double x)
{
    if (x>EPS)
        return 1;
    if (x<-EPS)
        return -1;
    return 0;
}

struct Set
{
    double v,u,w;
    void get ()
    {
		scanf("%lf%lf%lf",&v,&u,&w);
	}
}data[NUM];

struct Point
{
    double x,y;
 
    Point(){}
    Point(double _x,double _y)
    {
        x=_x;
        y=_y;
    }
}p[NUM],q[NUM];

int n;
double r;
int cCnt,curCnt;
bool flag,judge;

Point intersect (Point x,Point y,double a,double b,double c)  //相交
{
    double u = fabs(a * x.x + b * x.y + c);
    double v = fabs(a * y.x + b * y.y + c);
    return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );
}

/*半平面相交(直线切割多边形)(点标号从1开始)*/
void cut (double a,double b ,double c)
{
	int i;
	curCnt = 0;
	for (i=1;i<=cCnt;i++)
	{
        if (DB(a*p[i].x + b*p[i].y + c) >= 0)      //大于0为可行域
			q[++curCnt] = p[i];
        else
		{
            if (DB(a*p[i-1].x + b*p[i-1].y + c) > 0)
                q[++curCnt] = intersect(p[i],p[i-1],a,b,c);
            if (DB(a*p[i+1].x + b*p[i+1].y + c) > 0)
                q[++curCnt] = intersect(p[i],p[i+1],a,b,c);
        }
    }
   for (i=1;i<=curCnt;i++)
		p[i] = q[i];
    p[curCnt+1] = q[1];
	p[0] = p[curCnt];
    cCnt = curCnt;
	double area=0;
	for (i=1;i<=curCnt;i++)
		area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;
	area = fabs(area / 2.0);
	if (area < EPS)
		flag=false;
}

int main ()
{
	while (~scanf("%d",&n))
	{
		int i,j;
		for (i=1;i<=n;i++)
			data[i].get();
		for (i=1;i<=n;i++)
		{
			flag=true;
			judge=true;
			p[1] = Point(0,0);
			p[2] = Point(0,1000000);
			p[3] = Point(1000000,1000000);
			p[4] = Point(1000000,0);
			p[5] = p[1];
			p[0] = p[4];
			cCnt = 4;
			for (j=1;j<=n;j++)
			{
				if (i == j)
					continue;
				double A=(data[j].v-data[i].v)/(data[j].v*data[i].v);//1.0/data[i].v-1.0/data[j].v;
				double B=(data[j].u-data[i].u)/(data[j].u*data[i].u);//1.0/data[i].u-1.0/data[j].u;
				double C=(data[j].w-data[i].w)/(data[j].w*data[i].w);//1.0/data[i].w-1.0/data[j].w;
				A=-A;   //我的模板要求Ax+By+C的可行域为>0,本题要求<0
				B=-B;
				C=-C;

				if (A==0 && B==0 && C==0)
				{
					judge=false;
					break;
				}
				cut(A,B,C);
			}
			if (judge && flag)
				printf("Yes\n");
			else
				printf("No\n");
		}
	}
	return 0;
}

/*
11
10 2 6
10 2 6
10 2 6
10 7 3
5 6 7
3 2 7
6 2 6
3 5 7
8 4 6
10 4 2
1 8 7

Out

No
No
No
Yes
Yes
No
No
No
Yes
No
Yes
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: