poj1755 半平面交解不等式

题意

给你n个人铁人三项的速度(n<=100),每项比赛长度可调节,问你对于每个人来说,调节比赛长度这个人有没有获胜(比剩下人都快)的可能。

思路

三项速度设为ui,vi,wi 长度a b c

t = a / ux + b / vx + c / wx;

获胜需满足对于所有i:  (1/ux - 1/ui)*a + (1/vx - 1/vi)*b + (1/wx - 1/wi)*c < 0 已知c!=0,那么可将c除过去

即 (1/ux - 1/ui)*a/c + (1/vx - 1/vi)*b/c + (1/wx - 1/wi) < 0,那么就转换为求n-1条ax+by+c<0的不等式是否有可行性区域。

这里init四个边界点:(0,0) (inf,0) (inf,inf) (0,inf) 因为可行的答案比赛长度一定正数,此时半平面交n^2求是否有凸核M >= 3就ok了

上代码!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;
const double eps = 1e-6;
const double pi = acos(-1.0);
const double inf = 1.0 * 0x3f3f3f3f;
const int MaxN = 555;

int n,M;
double u[MaxN],v[MaxN],w[MaxN];
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}a[MaxN],p[MaxN],C[MaxN];
typedef Point Vector;

struct Line{
	Point s,e;
	Line() {}
	Line(Point a,Point b){ s = a,e = b;}
}L[MaxN];

struct NODE{
	double a,b,c;
};

int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}

//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

double dis(Point A,Point B){
	return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}

void init(){
	p[1].x = 0.0,p[1].y = 0.0;
	p[2].x = inf,p[2].y = 0.0;
	p[3].x = inf,p[3].y = inf;
	p[4].x = 0,p[4].y = inf;
	p[5] = p[1],p[0] = p[4];
}

Point Ist_LP(Line a,double a2,double b2,double c2){//给两直线求交点
	double a1 = a.e.y - a.s.y,b1 = a.s.x - a.e.x,c1 = a.e.x * a.s.y - a.s.x * a.e.y;
//	double a2 = b.s.y - b.e.y,b2 = b.e.x - b.s.x,c2 = b.s.x * b.e.y - b.e.x * b.s.y;
	return Point((c1*b2 - c2*b1)/(a2*b1 - a1*b2), (a2*c1 - a1*c2)/(a1*b2 - a2*b1));
}

NODE get_abc(Line X){
	NODE cur;
	Point S = X.s,E = X.e;
	cur.a = E.y - S.y;//后y - 前y
	cur.b = S.x - E.x;//前x - 后x
	cur.c = S.y*E.x - S.x*E.y;//前y*后x - 前x*后y
	return cur;
}

void cut(double a,double b,double c){
	int cnt = 0;//这把cut完的凸核还剩几个点
	for(int i = 1;i <= M; i++){
		if(a * p[i].x + b * p[i].y + c <= 0){
			C[++cnt] = p[i];//这次cur产生的点数组
		}//<=0:p[i]点在平移后的直线的左边 √
		else{
			//当前点与前后临接点 与平移后的直线相交
			//这里不需要= 都=了还求个锤子交点那不是直接放进去了
			if(a * p[i - 1].x + b * p[i - 1].y + c < 0){
				C[++cnt] = Ist_LP((Line){p[i-1],p[i]},a,b,c);
			}	
			if(a * p[i + 1].x + b * p[i + 1].y + c < 0){
				C[++cnt] = Ist_LP((Line){p[i],p[i+1]},a,b,c);//那得给整个点吧
			}
		}
	}
	for(int i = 1;i <= cnt; i++) p[i] = C[i];
	p[0] = C[cnt];
	p[cnt + 1] = C[1];//p[]存的是上一次cut完剩下的点 环数组
	M = cnt;
}

bool HalfPlane(int x){//半平面交
	M = 4;//4个边界
	for(int i = 1;i <= n; i++){
		if(i == x) continue;
		if(u[i] >= u[x] && v[i] >= v[x] && w[i] >= w[x]) return 0;
	}//三项都比你快 你还和人家比个锤子 别丢人了GG
	for(int i = 1;i <= n;i++){
		if(i == x) continue;//判断剩下n-1个表达式是否有可行性区域
		double a = (u[i] - u[x]) / (u[x] * u[i]);
		double b = (v[i] - v[x]) / (v[x] * v[i]);
		double c = (w[i] - w[x]) / (w[x] * w[i]);
		cut(a,b,c);
		if(M <= 2) return 0;
	}
	return M >= 3;
}

int main(){
	scanf("%d",&n);
	for(int i = 1;i <= n; i++){
		scanf("%lf%lf%lf",&u[i],&v[i],&w[i]);
	}
	for(int i = 1;i <= n; i++){
		init();
		if(HalfPlane(i)) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值