UVA12296 Pieces and Discs

题意

PDF

分析

可以看成直线切割多边形,直接维护。

对每个多边形考虑每条边和每个点即可。

时间复杂度?不过\(n,m \leq 20\)这种数据怎么都过了。据说是\(O(n^3)\)的,而且常数也挺小。

一般的比赛估计不会出这种vector套vector的神题。

代码

注意初始化的时候的那个初始长方形的点必须按逆时针顺序来插入。

我写反了,导致调了一晚上。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
	rg T data=0;
	rg int w=1;
	rg char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		data=data*10+ch-'0';
		ch=getchar();
	}
	return data*w;
}
template<class T>T read(T&x)
{
	return x=read<T>();
}
using namespace std;
typedef long long ll;

co double eps=1e-8;

int dcmp(double x)
{
	return fabs(x)<eps?0:(x<0?-1:1);
}

struct Point
{
	double x,y;
	
	Point(double x=0,double y=0)
	:x(x),y(y){};
};
typedef Point Vector;
typedef vector<Point> Polygon;

Vector operator+(co Vector&A,co Vector&B)
{
	return Vector(A.x+B.x,A.y+B.y);
}

Vector operator-(co Vector&A,co Vector&B)
{
	return Vector(A.x-B.x,A.y-B.y);
}

Vector operator*(co Vector&A,double p)
{
	return Vector(A.x*p,A.y*p);
}

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

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

double Length2(co Vector&A)
{
	return Dot(A,A);
}

Point LineLineIntersection(co Point&P,co Vector&v,co Point&Q,co Vector&w)
{
	Vector u=P-Q;
	double t=Cross(w,u)/Cross(v,w);
	return P+v*t;
}

bool OnSegment(co Point&p,co Point&a1,co Point&a2)
{
	return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}

double PolygonArea(co Polygon&poly)
{
	double area=0;
	int n=poly.size();
	for(int i=1;i<n-1;++i)
		area+=Cross(poly[i]-poly[0],poly[(i+1)%n]-poly[0]);
	return area/2;
}

Polygon CutPolygon(co Polygon&poly,co Point&A,co Point&B)
{
	Polygon newpoly;
	int n=poly.size();
	for(int i=0;i<n;++i)
	{
		co Point&C=poly[i];
		co Point&D=poly[(i+1)%n];
		if(dcmp(Cross(B-A,C-A))>=0)
			newpoly.push_back(C);
		if(dcmp(Cross(B-A,C-D))!=0)
		{
			Point ip=LineLineIntersection(A,B-A,C,D-C);
			if(OnSegment(ip,C,D))
				newpoly.push_back(ip);
		}
	}
	return newpoly;
}

int PointInPolygon(co Point&p,co Polygon&v)
{
	int wn=0;
	int n=v.size();
	for(int i=0;i<n;++i)
	{
		if(OnSegment(p,v[i],v[(i+1)%n]))
			return -1;
		int k=dcmp(Cross(v[(i+1)%n]-v[i],p-v[i]));
		int d1=dcmp(v[i].y-p.y);
		int d2=dcmp(v[(i+1)%n].y-p.y);
		if(k>0&&d1<=0&&d2>0)
			++wn;
		if(k<0&&d2<=0&&d1>0)
			--wn;
	}
	if(wn!=0)
		return 1;
	return 0;
}


bool InCircle(co Point&p,co Point&center,double R)
{
	return dcmp(Length2(p-center)-R*R)<0;
}

int LineCircleIntersection(co Point&A,co Point&B,co Point&C,double r,double&t1,double&t2)
{
	double a=B.x-A.x,
		   b=A.x-C.x,
		   c=B.y-A.y,
		   d=A.y-C.y;
	
	double e=a*a+c*c,
		   f=2*(a*b+c*d),
		   g=b*b+d*d-r*r,
		   delta=f*f-4*e*g;
	if(dcmp(delta)<0)
		return 0;
	if(dcmp(delta)==0)
	{
		t1=t2=-f/(2*e);
		return 1;
	}
	t1=(-f-sqrt(delta))/(2*e);
	t2=(-f+sqrt(delta))/(2*e);
	return 2;
}

bool CircleIntersectSegment(co Point&A,co Point&B,co Point&p,double R)
{
	double t1,t2;
	int c=LineCircleIntersection(A,B,p,R,t1,t2);
	if(c<=1)
		return 0;
	if(dcmp(t1)>0&&dcmp(t1-1)<0)
		return 1;
	if(dcmp(t2)>0&&dcmp(t2-1)<0)
		return 1;
	return 0;
}

vector<Polygon> pieces,new_pieces;

void Cut(int x1,int y1,int x2,int y2)
{
	new_pieces.clear();
	for(int i=0;i<pieces.size();++i)
	{
		Polygon left=CutPolygon(pieces[i],Point(x1,y1),Point(x2,y2));
		Polygon right=CutPolygon(pieces[i],Point(x2,y2),Point(x1,y1));
		if(left.size()>=3)
			new_pieces.push_back(left);
		if(right.size()>=3)
			new_pieces.push_back(right);
//		cerr<<"left="<<endl;
//		for(int j=0;j<left.size();++j)
//			cerr<<" "<<left[j].x<<","<<left[j].y;
//		cerr<<endl;
//		cerr<<"right="<<endl;
//		for(int j=0;j<right.size();++j)
//			cerr<<" "<<right[j].x<<","<<right[j].y;
//		cerr<<endl;
	}
	pieces=new_pieces;
}

bool DiscIntersectPolygon(co Polygon&poly,co Point&p,double R)
{
	if(PointInPolygon(p,poly)!=0)
		return 1;
	if(InCircle(poly[0],p,R))
		return 1;
	int n=poly.size();
	for(int i=0;i<n;++i)
	{
		if(CircleIntersectSegment(poly[i],poly[(i+1)%n],p,R))
			return 1;
		if(InCircle((poly[i]+poly[(i+1)%n])*0.5,p,R))
			return 1;
	}
	return 0;
}

void Query(co Point&p,int R)
{
	vector<double>ans;
	for(int i=0;i<pieces.size();++i)
		if(DiscIntersectPolygon(pieces[i],p,R))
			ans.push_back(fabs(PolygonArea(pieces[i])));
	printf("%d",ans.size());
	sort(ans.begin(),ans.end());
	for(int i=0;i<ans.size();++i)
		printf(" %.2lf",ans[i]);
	printf("\n");
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int n,m,L,W;
	while(read(n)|read(m)|read(L)|read(W))
	{
//		cerr<<"n="<<n<<" m="<<m<<" L="<<L<<" W="<<W<<endl;
		pieces.clear();
		
		Polygon bbox;
		bbox.push_back(Point(0,0)); // edit 1:must follow the order
		bbox.push_back(Point(L,0));
		bbox.push_back(Point(L,W));
		bbox.push_back(Point(0,W));
		pieces.push_back(bbox);
		
		for(int i=0;i<n;++i)
		{
			int x1,y1,x2,y2;
			read(x1),read(y1),read(x2),read(y2);
//			cerr<<"x1="<<x1<<" y1="<<y1<<" x2="<<x2<<" y2="<<y2<<endl;
			Cut(x1,y1,x2,y2);		
//			for(int i=0;i<pieces.size();++i)
//			{
//				cerr<<i<<" poly="<<endl;
//				for(int j=0;j<pieces[i].size();++j)
//					cerr<<" "<<pieces[i][j].x<<","<<pieces[i][j].y;
//				cerr<<endl;
//			}
		}
		
		for(int i=0;i<m;++i)
		{
			int x,y,R;
			read(x),read(y),read(R);
			Query(Point(x,y),R);
		}
		printf("\n");
	}
	return 0;
}

posted on 2018-12-26 22:47  autoint  阅读(195)  评论(0编辑  收藏  举报

导航