半平面交题目汇总

在此处总结关于半平面交的题目(基本都是POJ的):

目录

POJ-1279-Art Gallery(测板子)

POJ-1474-Video Surveillance(测半平面相交板子)

POJ-1755-(NO AC)

POJ-2104-(NO AC)

POJ-2187-(NO AC)

POJ-2451-(NO AC)

POJ-3130-How I Mathematician Wonder What You Are!(测板子)

POJ-3335-Rotating Scoreboard(板子)

POJ-3384-(NO AC)

POJ-3525-Most Distant Point from the Sea(二分向量平移半平面交)

POJ-3968-(NO AC)


POJ-1279-Art Gallery(测板子)

题目链接:http://poj.org/problem?id=1279

题目大意:顺时针||逆时针,给出n个点,围成一个多边形(不一定是凸多边形),问这个多边形的核的面积是多少(中间能够观测到所有点的面积)。

思路:板子,改一下就好了。

ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e4+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-12;
 
struct Point{//点的表示 
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y); 
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
	friend int operator == (const Point &a,const Point &b){
		return fabs(a.x-b.x)<EPS&&fabs(a.y-b.y)<EPS;
	}
}convex[MAXN];
struct V{//向量的表示 
	Point start,end;
	double ang;//角度,[-180,180] 
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	} 
}l[MAXN],st[MAXN];
struct Triangle{
	Point A,B,C;
};
int n,ccnt;
 
double DotMul(V a,V b){//点积 
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.x+a.end.y*b.end.y;
}
double CroMul(V a,V b){//叉积 a×b 
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.y-b.end.x*a.end.y;
}
int IsLineInter(V l1,V l2){//相交 
	if(max(l1.start.x,l1.end.x)>=min(l2.start.x,l2.end.x)&&
	max(l2.start.x,l2.end.x)>=min(l1.start.x,l1.end.x)&&
	max(l1.start.y,l1.end.y)>=min(l2.start.y,l2.end.y)&&
	max(l2.start.y,l2.end.y)>=min(l1.start.y,l1.end.y)){
		if(CroMul(l2,V(l2.start,l1.start))*CroMul(l2,V(l2.start,l1.end))<=0&&
		CroMul(l1,V(l1.start,l2.start))*CroMul(l1,V(l1.start,l2.end))<=0){
			return 1;
		}
	}return 0;
}
Point LineInterDot(V l1,V l2){//交点 
	Point p;
	double S1=CroMul(V(l1.start,l2.end),V(l1.start,l2.start));
	double S2=CroMul(V(l1.end,l2.start),V(l1.end,l2.end));
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
int JudgeOut(const V &x,const Point &p){//点在线的左侧 
	return CroMul(V(x.start,p),x)>EPS;//点在左侧返回0,右侧返回1 
}
int Parellel(const V &x,const V &y){//平行 
	return fabs(CroMul(x,y))<EPS;
}
void ChangeDirection(){
	for(int i=1;i<n;++i){
		swap(l[i].start,l[i].end);
	}
}
double CheckDirection(){
	double ans=0;
	for(int i=0;i<n;++i){//判断是否是顺时针 
		ans+=CroMul(V(Point(0,0),l[i].start),V(Point(0,0),l[i].end));
	}return ans;//ans>0逆时针,sum<0顺时针 
}
int Cmp(V a,V b){
	if(fabs(a.ang-b.ang)<EPS){//角度相同时,不同的边在不同的位置 
		//此时有两种return方式, 
		//return CorMul(a,V(b.end-a.start))>=0;
		//左边的边在后面的位置,这样的话,进行计算的时候就可以忽略 相同角度边的影响了 
		return CroMul(V(b.end-a.start),V(a.end-b.start))>EPS;
		//左边的边在前面的位置,要进行进行去重判断 。 
	}
	return a.ang<b.ang;
}
double HplaneIntersection(){
	int top=1,bot=0;
	sort(l,l+n,Cmp);
	int tmp=1;
	for(int i=1;i<n;++i){
		if(l[i].ang-l[i-1].ang>EPS){//去重,如果该边和前面的边平行,则忽略。 
			l[tmp++]=l[i];
		}
	}n=tmp;
	st[0]=l[0];st[1]=l[1];
	for(int i=2;i<n;++i){
		if(Parellel(st[top],st[top-1])||Parellel(st[bot],st[bot+1])) return 0;
		while(bot<top&&JudgeOut(l[i],LineInterDot(st[top],st[top-1]))) --top;
		while(bot<top&&JudgeOut(l[i],LineInterDot(st[bot],st[bot+1]))) ++bot;
//		while(bot<top&&(Parellel(st[top],st[top-1])||JudgeOut(l[i],LineInterDot(st[top],st[top-1])))) --top;
//		while(bot<top&&(Parellel(st[bot],st[bot+1])||JudgeOut(l[i],LineInterDot(st[bot],st[bot+1])))) ++bot;
		st[++top]=l[i];
	}
//	while(bot<top&&(Parellel(st[top],st[top-1])||JudgeOut(st[bot],LineInterDot(st[top],st[top-1])))) --top;
//	while(bot<top&&(Parellel(st[bot],st[bot+1])||JudgeOut(st[top],LineInterDot(st[bot],st[bot+1])))) ++bot;
	while(bot<top&&JudgeOut(st[bot],LineInterDot(st[top],st[top-1]))) --top;
	while(bot<top&&JudgeOut(st[top],LineInterDot(st[bot],st[bot+1]))) ++bot;
	if(top<=bot+1) return 0.00;
	st[++top]=st[bot];
	ccnt=0;
	for(int i=bot;i<top;++i){
		convex[ccnt++]=LineInterDot(st[i],st[i+1]);
	}double ans=0;
	convex[ccnt]=convex[0];
	for(int i=0;i<ccnt;++i){
		ans+=CroMul(V(Point(0,0),convex[i]),V(Point(0,0),convex[i+1]));
	}return ans/2.0;
}
int main(){
	int Case=1,T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%lf%lf",&l[0].end.x,&l[0].end.y);
		l[n-1].start.x=l[0].end.x;l[n-1].start.y=l[0].end.y;
		for(int i=1;i<n;++i){
			scanf("%lf%lf",&l[i].end.x,&l[i].end.y);
			l[i-1].start.x=l[i].end.x;l[i-1].start.y=l[i].end.y;
		}
		for(int i=0;i<n;++i){
			l[i].ang=atan2(l[i].end.y-l[i].start.y,l[i].end.x-l[i].start.x);
		}
		if(CheckDirection()<0)
			ChangeDirection();//改成逆时针
		//默认从点在线的左边。
		double ans=HplaneIntersection();ans=fabs(ans);
		printf("%.2f\n",ans);
	}
}
/*
*/

POJ-1474-Video Surveillance(测半平面相交板子)

题目连接:http://poj.org/problem?id=1474

题目大意:给出n个点,围成了一个多边形(点的顺序逆时针||顺时针输入)让你判断能不能找到一点,能够从多边形内部观察整个多边形(求多边形的核)

思路:这个就是个板子,复制上就行了。

Code:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-12;
 
struct Point{//点的表示 
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y); 
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
	friend Point operator == (const Point &a,const Point &b){
		return fabs(a.x-b.x)<EPS&&fabs(a.y-b.y)<EPS;
	}
}convex[MAXN];
struct V{//向量的表示 
	Point start,end;
	double ang;//角度,[-180,180] 
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	} 
}l[MAXN],st[MAXN];
struct Triangle{
	Point A,B,C;
};
int n,ccnt;
 
double DotMul(V a,V b){//点积 
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.x+a.end.y*b.end.y;
}
double CroMul(V a,V b){//叉积 a×b 
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.y-b.end.x*a.end.y;
}
int IsLineInter(V l1,V l2){//相交 
	if(max(l1.start.x,l1.end.x)>=min(l2.start.x,l2.end.x)&&
	max(l2.start.x,l2.end.x)>=min(l1.start.x,l1.end.x)&&
	max(l1.start.y,l1.end.y)>=min(l2.start.y,l2.end.y)&&
	max(l2.start.y,l2.end.y)>=min(l1.start.y,l1.end.y)){
		if(CroMul(l2,V(l2.start,l1.start))*CroMul(l2,V(l2.start,l1.end))<=0&&
		CroMul(l1,V(l1.start,l2.start))*CroMul(l1,V(l1.start,l2.end))<=0){
			return 1;
		}
	}return 0;
}
Point LineInterDot(V l1,V l2){//交点 
	Point p;
	double S1=CroMul(V(l1.start,l2.end),V(l1.start,l2.start));
	double S2=CroMul(V(l1.end,l2.start),V(l1.end,l2.end));
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
int JudgeOut(const V &x,const Point &p){//点在线的左侧 
	return CroMul(V(x.start,p),x)>EPS;//点在左侧返回0,右侧返回1 
}
int Parellel(const V &x,const V &y){//平行 
	return fabs(CroMul(x,y))<EPS;
}
void ChangeDirection(){
	for(int i=1;i<n;++i){
		swap(l[i].start,l[i].end);
	}
}
double CheckDirection(){
	double ans=0;
	for(int i=0;i<n;++i){//判断是否是顺时针 
		ans+=CroMul(V(Point(0,0),l[i].start),V(Point(0,0),l[i].end));
	}return ans;//ans>0逆时针,sum<0顺时针 
}
int Cmp(V a,V b){
	if(fabs(a.ang-b.ang)<EPS){//角度相同时,不同的边在不同的位置 
		//此时有两种return方式, 
		//return CorMul(a,V(b.end-a.start))>=0;
		//左边的边在后面的位置,这样的话,进行计算的时候就可以忽略 相同角度边的影响了 
		return CroMul(V(b.end-a.start),V(a.end-b.start))>EPS;
		//左边的边在前面的位置,要进行进行去重判断 。 
	}
	return a.ang<b.ang;
}
double HplaneIntersection(){
	int top=1,bot=0;
	sort(l,l+n,Cmp);
	int tmp=1;
	for(int i=1;i<n;++i){
		if(l[i].ang-l[i-1].ang>EPS){//去重,如果该边和前面的边平行,则忽略。 
			l[tmp++]=l[i];
		}
	}n=tmp;
	st[0]=l[0];st[1]=l[1];
	for(int i=2;i<n;++i){
		if(Parellel(st[top],st[top-1])||Parellel(st[bot],st[bot+1])) return 0;
		while(bot<top&&JudgeOut(l[i],LineInterDot(st[top],st[top-1]))) --top;
		while(bot<top&&JudgeOut(l[i],LineInterDot(st[bot],st[bot+1]))) ++bot;
		st[++top]=l[i];
	}
//	while(bot<top&&(Parellel(st[top],st[top-1])||JudgeOut(st[bot],LineInterDot(st[top],st[top-1])))) --top;
//	while(bot<top&&(Parellel(st[bot],st[bot+1])||JudgeOut(st[top],LineInterDot(st[bot],st[bot+1])))) ++bot;
	while(bot<top&&JudgeOut(st[bot],LineInterDot(st[top],st[top-1]))) --top;
	while(bot<top&&JudgeOut(st[top],LineInterDot(st[bot],st[bot+1]))) ++bot;
	if(top<=bot+1) return 0.00;
	return 1;
	st[++top]=st[bot];
	ccnt=0;
	for(int i=bot;i<top;++i){
		convex[ccnt++]=LineInterDot(st[i],st[i+1]);
	}double ans=0;
	convex[ccnt]=convex[0];
	for(int i=0;i<ccnt;++i){
		ans+=CroMul(V(Point(0,0),convex[i]),V(Point(0,0),convex[i+1]));
	}return ans/2;
}
int main(){
	int Case=1;
	while(~scanf("%d",&n)){
		if(n==0) break;
		scanf("%lf%lf",&l[0].end.x,&l[0].end.y);
		l[n-1].start.x=l[0].end.x;l[n-1].start.y=l[0].end.y;
		for(int i=1;i<n;++i){
			scanf("%lf%lf",&l[i].end.x,&l[i].end.y);
			l[i-1].start.x=l[i].end.x;l[i-1].start.y=l[i].end.y;
		}
		for(int i=0;i<n;++i){
			l[i].ang=atan2(l[i].end.y-l[i].start.y,l[i].end.x-l[i].start.x);
		}
		if(CheckDirection()<0)
			ChangeDirection();//改成逆时针
		//默认从点在线的左边。
		if(HplaneIntersection()) printf("Floor #%d\nSurveillance is possible.\n\n",Case++);
		else printf("Floor #%d\nSurveillance is impossible.\n\n",Case++);
	}
}

POJ-1755-(NO AC)

POJ-2104-(NO AC)

POJ-2187-(NO AC)

POJ-2451-(NO AC)

POJ-3130-How I Mathematician Wonder What You Are!(测板子)

题目链接:http://poj.org/problem?id=3130

题目大意:给出n个点,判断这n个点组成的多边形是否存在一个面积大于0的核,是则输出1,否则输出0;

思路:上道题,YES改成1,NO改成0即可。

ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-12;

struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
}Dot[MAXN];
struct V{
	Point start,end;double ang;
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0.0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	}
}Edge[MAXN],stk[MAXN];
int n;

double CroMul(V a,V b){
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.y-a.end.y*b.end.x;
}
double CheckDirection(){
	double ans=0;
	for(int i=0;i<n;++i){
		ans+=CroMul(V(Point(0,0),Edge[i].start),V(Point(0,0),Edge[i].end));
	}return ans;
}
void ChangeDirection(){
	for(int i=0;i<n;++i){
		swap(Edge[i].start,Edge[i].end);
	}
}
int Parellel(const V &a,const V &b){
	return fabs(CroMul(a,b))<EPS;
}
Point LineInterDot(const V &l1,const V &l2){
	Point p;
	double S1=CroMul(V(l1.start,l2.end),V(l1.start,l2.start));
	double S2=CroMul(V(l1.end,l2.start),V(l1.end,l2.end));
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
int JudgeOut(const V &x,const Point &p){//判断点在线的左侧 
	return CroMul(V(x.start,p),x)>EPS;//点在线的左侧,return 0,else return 1 
}
int Cmp(V a,V b){
	if(fabs(a.ang-b.ang)<EPS)
		return CroMul(V(b.end-a.start),V(a.end-b.start))>EPS;
	return a.ang<b.ang;
}
int HplaneIntersection(){
	int top=1,bot=0;
	sort(Edge,Edge+n,Cmp);
	int temp=1;
	for(int i=1;i<n;++i){
		if(fabs(Edge[i].ang-Edge[i-1].ang)>EPS){
			Edge[temp++]=Edge[i];
		}
	}n=temp;
	stk[0]=Edge[0];stk[1]=Edge[1];
	for(int i=2;i<n;++i){
		if(Parellel(stk[top],stk[top-1])||Parellel(stk[bot],stk[bot+1])) return 0;
		while(bot<top&&JudgeOut(Edge[i],LineInterDot(stk[top],stk[top-1]))) --top;
		while(bot<top&&JudgeOut(Edge[i],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
		stk[++top]=Edge[i];
	}
	while(bot<top&&JudgeOut(stk[bot],LineInterDot(stk[top],stk[top-1]))) --top;
	while(bot<top&&JudgeOut(stk[top],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
	if(top<=bot+1) return 0;
	return 1;
}
int main(){
	while(~scanf("%d",&n)){
		if(n==0) break;
		scanf("%lf%lf",&Edge[0].end.x,&Edge[0].end.y);
		Edge[n-1].start.x=Edge[0].end.x;
		Edge[n-1].start.y=Edge[0].end.y;
		for(int i=1;i<n;++i){
			scanf("%lf%lf",&Edge[i].end.x,&Edge[i].end.y);
			Edge[i-1].start.x=Edge[i].end.x;
			Edge[i-1].start.y=Edge[i].end.y;
		}
		for(int i=0;i<n;++i){
			Edge[i].ang=atan2(Edge[i].end.y-Edge[i].start.y,Edge[i].end.x-Edge[i].start.x);
		}
		if(CheckDirection()<0) ChangeDirection();
		if(HplaneIntersection()) printf("1\n");
		else printf("0\n");
	}
}
/*

*/

POJ-3335-Rotating Scoreboard(板子)

题目链接:http://poj.org/problem?id=3335

题目大意:顺时针||逆时针给出一些点,然后判断这些点构成的多边形是否存在面积大于0的核。存在输出“YES”,否则输出“NO”。

思路:板子,照着抄就行了

ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")
  
#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e3+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-12;

struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
}Dot[MAXN];
struct V{
	Point start,end;double ang;
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0.0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	}
}Edge[MAXN],stk[MAXN];
int n;

double CroMul(V a,V b){
	a.end=a.end-a.start;b.end=b.end-b.start;
	return a.end.x*b.end.y-a.end.y*b.end.x;
}
double CheckDirection(){
	double ans=0;
	for(int i=0;i<n;++i){
		ans+=CroMul(V(Point(0,0),Edge[i].start),V(Point(0,0),Edge[i].end));
	}return ans;
}
void ChangeDirection(){
	for(int i=0;i<n;++i){
		swap(Edge[i].start,Edge[i].end);
	}
}
int Parellel(const V &a,const V &b){
	return fabs(CroMul(a,b))<EPS;
}
Point LineInterDot(const V &l1,const V &l2){
	Point p;
	double S1=CroMul(V(l1.start,l2.end),V(l1.start,l2.start));
	double S2=CroMul(V(l1.end,l2.start),V(l1.end,l2.end));
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
int JudgeOut(const V &x,const Point &p){//判断点在线的左侧 
	return CroMul(V(x.start,p),x)>EPS;//点在线的左侧,return 0,else return 1 
}
int Cmp(V a,V b){
	if(fabs(a.ang-b.ang)<EPS)
		return CroMul(V(b.end-a.start),V(a.end-b.start))>EPS;
	return a.ang<b.ang;
}
int HplaneIntersection(){
	int top=1,bot=0;
	sort(Edge,Edge+n,Cmp);
	int temp=1;
	for(int i=1;i<n;++i){
		if(fabs(Edge[i].ang-Edge[i-1].ang)>EPS){
			Edge[temp++]=Edge[i];
		}
	}n=temp;
	stk[0]=Edge[0];stk[1]=Edge[1];
	for(int i=2;i<n;++i){
		if(Parellel(stk[top],stk[top-1])||Parellel(stk[bot],stk[bot+1])) return 0;
		while(bot<top&&JudgeOut(Edge[i],LineInterDot(stk[top],stk[top-1]))) --top;
		while(bot<top&&JudgeOut(Edge[i],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
		stk[++top]=Edge[i];
	}
	while(bot<top&&JudgeOut(stk[bot],LineInterDot(stk[top],stk[top-1]))) --top;
	while(bot<top&&JudgeOut(stk[top],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
	if(top<=bot+1) return 0;
	return 1;
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		scanf("%lf%lf",&Edge[0].end.x,&Edge[0].end.y);
		Edge[n-1].start.x=Edge[0].end.x;
		Edge[n-1].start.y=Edge[0].end.y;
		for(int i=1;i<n;++i){
			scanf("%lf%lf",&Edge[i].end.x,&Edge[i].end.y);
			Edge[i-1].start.x=Edge[i].end.x;
			Edge[i-1].start.y=Edge[i].end.y;
		}
		for(int i=0;i<n;++i){
			Edge[i].ang=atan2(Edge[i].end.y-Edge[i].start.y,Edge[i].end.x-Edge[i].start.x);
		}
		if(CheckDirection()<0) ChangeDirection();
		if(HplaneIntersection()) printf("YES\n");
		else printf("NO\n");
	}
}
/*

*/

POJ-3384-(NO AC)

POJ-3525-Most Distant Point from the Sea(二分向量平移半平面交)

题目链接:http://poj.org/problem?id=3525

题目大意:给出一个凸多边形,然后输出这个凸多边形的最大的内接圆的半径。

思路:首先确定有一个内接圆,然后每次多边形向内收缩,收缩到没有半平面交的时候,这个收缩的长度就是半径了。

哎,看着道题的时候看了一下讨论区。。结果就直接二分了,就是向量平移的那一段想了会,不错的一道题。

ACCode:

// luogu-judger-enable-o2
//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include<stdio.h>
#include<string.h> 
#include<math.h> 
   
//#include<map>  
#include<set>
#include<deque> 
#include<queue> 
#include<stack> 
#include<bitset>
#include<string> 
#include<fstream>
#include<iostream> 
#include<algorithm> 
using namespace std; 
  
#define ll long long 
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
//  register
const int MAXN=1e2+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const int MOD=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-8;

struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
	friend Point operator + (const Point &a,const Point &b){
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator - (const Point &a,const Point &b){
		return Point(a.x-b.x,a.y-b.y);
	}
	friend double operator ^ (Point a,Point b){
		return a.x*b.y-a.y*b.x;
	}
}Dots[MAXN],Dots2[MAXN];
struct V{
	Point start,end;double ang;
	V(Point _start=Point(0,0),Point _end=Point(0,0),double _ang=0.0){
		start=_start;end=_end;ang=_ang;
	}
	friend V operator + (const V &a,const V &b){
		return V(a.start+b.start,a.end+b.end);
	}
	friend V operator - (const V &a,const V &b){
		return V(a.start-b.start,a.end-b.end);
	}
}Edge[MAXN],Edge2[MAXN],stk[MAXN];
struct Circle{
	double r;
	Point centre;
	Circle(Point _centre=Point(0,0),double _r=0){
		centre=_centre;r=_r;
	}
};
struct Triangle{
	Point A,B,C;
};
int n;

int CheckDirection(){
	double ans=0;
	for(int i=1;i<=n;++i){
		ans+=Edge[i].start^Edge[i].end;
	}return ans<0;//1逆时针 
}
void ChangeDirection(){
	for(int i=1;i<=n;++i){
		swap(Edge[i].start,Edge[i].end);
	}
}
int Parellel(const V &x,const V &y){
	return fabs((x.end-x.start)^(y.end-y.start))<EPS;
}
Point LineInterDot(const V &l1,const V &l2){
	Point p;
	double S1=(l2.end-l1.start)^(l2.start-l1.start);
	double S2=(l2.start-l1.end)^(l2.end-l1.end);
	p.x=(l1.start.x*S2+l1.end.x*S1)/(S1+S2);
	p.y=(l1.start.y*S2+l1.end.y*S1)/(S1+S2);
	return p;
}
int JudgeOut(const V &l1,const Point &p){
	return ((p-l1.start)^(l1.end-l1.start))>EPS;
}
int HplaneIntersection(){//半平面交板子
	int top=1,bot=0;
	stk[0]=Edge2[1];stk[1]=Edge2[2];
	for(int i=3;i<=n;++i){
		if(Parellel(stk[top],stk[top-1])||Parellel(stk[bot],stk[bot+1])) return 0;
		while(bot<top&&JudgeOut(Edge2[i],LineInterDot(stk[top],stk[top-1]))) --top;
		while(bot<top&&JudgeOut(Edge2[i],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
		stk[++top]=Edge2[i];
	}
	while(bot<top&&JudgeOut(stk[top],LineInterDot(stk[bot],stk[bot+1]))) ++bot;
	while(bot<top&&JudgeOut(stk[bot],LineInterDot(stk[top],stk[top-1]))) --top;
	if(top<=bot+1) return 0;
	return 1;
}
int Move(double mid){//平移
	for(int i=1;i<=n;++i){
		Edge2[i].start=Point(Edge[i].start.x+cos(Edge[i].ang+PI/2.0)*mid,Edge[i].start.y+sin(Edge[i].ang+PI/2.0)*mid);
		Edge2[i].end=Point(Edge[i].end.x+cos(Edge[i].ang+PI/2.0)*mid,Edge[i].end.y+sin(Edge[i].ang+PI/2.0)*mid);
	}return HplaneIntersection();
}
int Cmp(const V &l1,const V &l2){
	if(fabs(l1.ang-l2.ang)<EPS)
		return ((l2.end-l1.start)^(l1.end-l2.start))>EPS;
	return l1.ang<l2.ang;
}
int main(){
	while(~scanf("%d",&n)){
		if(n==0) break;
		double a,b;scanf("%lf%lf",&a,&b);
		Dots[1]=Point(a,b);
		for(int i=2;i<=n;++i){
			scanf("%lf%lf",&a,&b);
			Dots[i]=Point(a,b);
			Edge[i-1]=V(Dots[i],Dots[i-1]);
		}Edge[n]=V(Dots[1],Dots[n]);
		if(CheckDirection()) ChangeDirection();
		for(int i=1;i<=n;++i){
			Edge[i].ang=atan2(Edge[i].end.y-Edge[i].start.y,Edge[i].end.x-Edge[i].start.x);
		}sort(Edge+1,Edge+1+n,Cmp);int temp=2;
		for(int i=2;i<=n;++i){
			if(Edge[i].ang-Edge[i-1].ang>EPS){
				Edge[temp++]=Edge[i];
			}
		}n=temp-1;
		double l=0.00,r=10000.00,mid;
		while(l<r-EPS){
			mid=(l+r)/2.0;
			if(Move(mid))
				l=mid;
			else
				r=mid;
		}printf("%.6f\n",l);
	}
	
}
/*
4 2
0.5 0.5
10.5 0.5
10.5 10.5
0.5 10.5
1 3
4 2
*/

POJ-3968-(NO AC)

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/87921815
今日推荐