省选专练SCOI2015小凸想跑步

终于快把SCOI练完了。。。

毒瘤题

这个题难点不在半平面交,在于推导:


其次精度问题

eps 和INF 取值需谨慎。

大了会丢精度,小了会炸精度。

接着得开long double

于是流输出。

#include<bits/stdc++.h>
using namespace std;
#define double long double
const double INF=1e16;
const double eps=1e-16;
const int N=4e5;
/*int cmp(double x){
	if(fabs(x)<eps){
		return 0;
	}
	else return x>0?1:-1;
}
bool equal (double x,double y){
	return (cmp(x-y)==0);
}
struct Point{
	double x,y;
	Point (double _x=0,double _y=0):x(_x),y(_y){}
	friend Point operator + (Point A,Point B){return Point(A.x+B.x,A.y+B.y);}
	friend Point operator - (Point A,Point B){return Point(A.x-B.x,A.y-B.y);}
	friend Point operator * (Point A,double k){return Point(A.x*k,A.x*k);}
	friend Point operator / (Point A,double k){return Point(A.x/k,A.y/k);}
	double ang(){return (atan2(y,x));}
	void read(){scanf("%Lf%Lf",&x,&y);}
}p[N],a[N];
typedef Point Vector;
struct Line{
	Point p;
	Vector v;
	Line (Point _P=Point(0,0),Point _v=Vector(0,0)):p(_P),v(_v){}
	double Ang;
	double ang(){return v.ang();}
}l[N],convex_hull[N],temp[N];
bool comp(Line A,Line B){
	return A.Ang<B.Ang;
}
double Cross(Vector A,Vector B){
	return A.x*B.y-A.y*B.x;
}
bool in(Point p,Line l){
	return cmp(Cross(l.v,p-l.p))>=0;
}
Point getpot(Line A,Line B){
	return B.p+B.v*(Cross(A.v,A.p-B.p)/Cross(A.v,B.v));
}*/
struct Point{
	double x,y;
	Point(double _x=0,double _y=0):x(_x),y(_y){}
	friend Point operator +(Point A,Point B){return Point(A.x+B.x,A.y+B.y);}
	friend Point operator -(Point A,Point B){return Point(A.x-B.x,A.y-B.y);}
	friend Point operator *(Point A,double k){return Point(A.x*k,A.y*k);}
	friend Point operator /(Point A,double k){return Point(A.x/k,A.y/k);}
	double ang(){return atan2(y,x);}
	void read(){scanf("%lf%lf",&x,&y);x*=1.0;y*=1.0;}
}p[N],a[N];
int cmp(double x){
	if(fabs(x)<eps)return 0;
	return x>eps?1:-1;
}
bool equal(double x,double y){
	return cmp(x-y)==0;
}
typedef Point Vector;
struct Line{
	Point p;
	Vector v;
	Line(Point _p=Point(0,0),Vector _v=Vector(0,0)):v(_v),p(_p){}
	double Ang;
	double ang(){return v.ang();}
}l[N],temp[N],convex_hull[N];
bool comp(Line A,Line B){
	return A.Ang<B.Ang;
}
double Cross(Vector A,Vector B){
	return(double)(A.x*B.y-A.y*B.x);
}
Point getpot(Line A,Line B){
	return B.p+B.v*((double)Cross(A.v,A.p-B.p)/(double)Cross(A.v,B.v));
}
bool in(Point p,Line l){
	return cmp(Cross(l.v,p-l.p))>=0;
}
int n;
int lcnt=0;
double Area;
double squaring(int n,Point *p){
	double ans=0;
	for(int i=2;i<n;i++){
		ans+=Cross(p[i]-p[1],p[i+1]-p[1]);
//		cout<<a[i].x<<" "<<a[i].y<<endl; 
	}
	return fabs(ans/2);
}
int tot=0;
void Shrink(int &num){
	int siz=0;
	for(int i=1;i<=lcnt;i++){
		if(!siz){
			siz++;
			temp[siz]=l[i];
		}
		else{
			if(!(equal(temp[siz].Ang,l[i].Ang))){
				siz++;
				temp[siz]=l[i];
			}
			else{
				if(in(l[i].p,temp[siz])){
					temp[siz]=l[i];
				}
			}
		}
	}
	num=siz;
	for(int i=1;i<=siz;i++){
		l[i]=temp[i];
	}
}
void Half_Plane_Intersection(){
	sort(l+1,l+1+lcnt,comp);
	Shrink(lcnt);
	int head=1;
	int tail=2;
	convex_hull[1]=l[1];
	convex_hull[2]=l[2];
	for(int i=3;i<=lcnt;i++){
		while(head<tail&&!in(getpot(convex_hull[tail],convex_hull[tail-1]),l[i]))tail--;
		while(head<tail&&!in(getpot(convex_hull[head],convex_hull[head+1]),l[i]))head++;
		tail++;
		convex_hull[tail]=l[i];
	}
	while(head<tail&&!in(getpot(convex_hull[tail],convex_hull[tail-1]),convex_hull[head]))tail--;
	convex_hull[tail+1]=convex_hull[head];
	for(int i=head;i<=tail;i++){
		a[++tot]=getpot(convex_hull[i+1],convex_hull[i]);
	}
//	cout<<tot<<endl;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		p[i].x=x;
		p[i].y=y;
	}
	Area=squaring(n,p);
//	cout<<fixed<<setprecision(4)<<Area<<'\n';
	for(int i=2;i<=n;i++){
		int k1=i;
		int k2=i%n+1;//(1,n) 
		double A=p[1].y-p[2].y-p[k1].y+p[k2].y;
		double B=p[2].x-p[1].x-p[k2].x+p[k1].x;
		double C=(p[1].x*p[2].y-p[2].x*p[1].y-p[k1].x*p[k2].y+p[k2].x*p[k1].y);
		if(!cmp(A)&&!cmp(B))
			continue;
		if(!cmp(A)){//B*Y+C<=0
			if(cmp(B)>0){//Y<=(-(C/B))
				l[++lcnt]=Line(Point(INF,-(C/B)),Vector(-2*INF,0));
			}
			else{//Y>=(-(C/B))
				l[++lcnt]=Line(Point(-INF,-(C/B)),Vector(2*INF,0));
			}
			continue;
		}
		if(!cmp(B)){//A*X+C<=0
			if(cmp(A)>=0){
				l[++lcnt]=Line(Point(-(C/A),-INF),Vector(0,2*INF));
			}
			else{
				l[++lcnt]=Line(Point(-(C/A),INF),Vector(0,-2*INF));
			}
			continue;
		}
		//A*X+B*Y+C<=0
		double k=-(A/B);
		double b=-(C/B);
		//Y?=kx+b
		double x1=0;
		double x2=1;
		double y1=k*x1+b;
		double y2=k*x2+b;
		Point P=Point(x1,y1);
		Point Q=Point(x2,y2);
		if(cmp(-B)>0){
			l[++lcnt]=Line(P,Q-P);//Y>=kX+b
		}
		else{
			l[++lcnt]=Line(Q,P-Q);//Y<=kX+b
		}
	}
	//in the polygon
	for(int i=1;i<=n;i++){
		l[++lcnt]=Line(p[i],p[i%n+1]-p[i]);
	}
	for(int i=1;i<=lcnt;i++){
		l[i].Ang=l[i].ang();
	}
	Half_Plane_Intersection();
	double ans=squaring(tot,a);
	cout<<fixed<<setprecision(4)<<ans/Area;
}

中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.youkuaiyun.com/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.youkuaiyun.com/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值