在此处总结关于半平面交的题目(基本都是POJ的):
目录
POJ-1474-Video Surveillance(测半平面相交板子)
POJ-3130-How I Mathematician Wonder What You Are!(测板子)
POJ-3335-Rotating Scoreboard(板子)
POJ-3525-Most Distant Point from the Sea(二分向量平移半平面交)
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
*/