poj2540 半平面交求可行性区域解线性规划

题意:

现有一个[0,0]到[10,10]的方格子,已知这里面有一点火源,但你不知道其确切位置 你初始在(0,0) 每次移动到下一个点并告知你距离火源和上一次比较是更近还是更远或者Same。对于每次移动你需要给出目前火源可能在的区域面积。

思路:

每次找到lst与cur点的中垂线,显然hotter的一边计入答案与原先剩下的面积半平面交

求中垂线:

中点为mid,法向量Fa,中垂线向量(mid,end)  end = mid+Fa;

		Vector QAQ;
		QAQ.x = cur.x - lst.x,QAQ.y = cur.y - lst.y;
		Vector Fa = get_Fa(QAQ);
		Point mid;
		mid.x = (cur.x + lst.x)/2.0;
		mid.y = (cur.y + lst.y)/2.0;
		Point end = mid + Fa;//mid~end中垂线!

求法向量

Vector get_Fa(Vector Y){
	Vector Fa;
	if(!dcmp(Y.x - 0)){//原向量垂直
		Fa.x = 1,Fa.y = 0;
	}
	else if(!dcmp(Y.y - 0)){//原向量水平
		Fa.x = 0,Fa.y = 1;
	}
	else{
		Fa.x = 1;
		Fa.y = -1.0 * Y.x / Y.y;
	}
	return Fa;
}

法向量求出来后需要根据目前法向量的方向与Hotter/Colder判断是否需要调整法向量方向(因为我们cut是取向量左半部分) 

 判断现在法向量与cur点的关系:

bool compare(Point a,Point b,Point c){
	return Cross(c - a,c - b) > 0;//a在b顺时针>0
}
//判断cur点与直线的关系 cur点做轴!
bool vis = compare(mid,end,cur);

 这里要注意Same表示火源在中垂线上,不再存在可行性区域,至此往后0.00

上代码!

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

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

int n,M;
char s[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);
}
bool compare(Point a,Point b,Point c){
	return Cross(c - a,c - b) > 0;//a在b顺时针>0
}

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;
}

Vector get_Fa(Vector Y){
	Vector Fa;
	if(!dcmp(Y.x - 0)){//原向量垂直
		Fa.x = 1,Fa.y = 0;
	}
	else if(!dcmp(Y.y - 0)){//原向量水平
		Fa.x = 0,Fa.y = 1;
	}
	else{
		Fa.x = 1;
		Fa.y = -1.0 * Y.x / Y.y;
	}
	return Fa;
}

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;
}

double S_core(){//核面积
	double ans = 0.0;
	for(int i = 1;i <= M; i++){
		ans += Cross(p[i] - p[1],p[i + 1] - p[1]);
	}
	if(dcmp(ans) < 0) ans *= -1.0;
	return ans / 2.0;
}

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

int main(){
	bool flag = 0;
	init();
	Point lst,cur;
	lst.x = 0.0,lst.y = 0.0;
	while(~scanf("%lf%lf %s",&cur.x,&cur.y,s)){
		if(flag || s[0] == 'S'){
			flag = 1;
			printf("0.00\n");
			continue;
		}
		Vector QAQ;
		QAQ.x = cur.x - lst.x,QAQ.y = cur.y - lst.y;
		Vector Fa = get_Fa(QAQ);
		Point mid;
		mid.x = (cur.x + lst.x)/2.0;
		mid.y = (cur.y + lst.y)/2.0;
		Point end = mid + Fa;//mid~end中垂线!
		//调整法向量角度!!! 以保证半平面取左边
		bool vis = compare(mid,end,cur);
		if((vis && s[0] == 'C') || (!vis && s[0] == 'H')){
			Point tmp = mid;
			mid = end;
			end = tmp;
		}
		//求每次还剩的可行性区域
		NODE now = get_abc(Line(mid,end));
		cut(now.a,now.b,now.c);
		if(M >= 3) printf("%.2f\n",S_core());
		else{
			printf("0.00\n");
			flag = 1;
		}
		lst = cur;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值