Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
分数:2800+
Problem Description
You are given a simple polygon in a two-dimensional plane. Please check whether we can move at most one point such that the simple polygon becomes a line-symmetric simple polygon.
Note that you cannot reorder these points. If you move the i-th point, it still connects to the
-th point and the
-th point in the original order. Also, you cannot move a point to a location having an existing point.
Input
The first line contains an integer
indicating the number of tests.
Each test begins with one line containing one integer n, denoting the number of points in the polygon. Then, the
-th line in the following
lines contains two integers
is the coordinate of the i-th point. For any
, the
-th point is connected to the
-th point with an edge. Also, the n-th point is connected to the first point.
- coordinates are in the range
Output
For each test, if you can move at most one point making the polygon line-symmetric, print a character ‘Y’ in a line, otherwise print a character ‘N’ in a line. Please note that the final polygon also has to be a simple polygon.
Sample Input
3
3
1 1
1 2
2 2
4
1 1
1 2
2 2
2 1
7
10 0
5 1
6 2
2 3
2 8
11 7
8 5
Sample Output
Y
Y
N
题意:
给定一个简单多边形,问是否能够至多移动一个点的位置,使得这个多边形变为轴对称图形。
移动之后的点不能与其他已经存在的点重合,移动之后的新图形也要是简单多边形。
题解:
我们枚举所有相邻两个点或者间隔为1的两个点作为被对称轴垂直平分的那个底。然后对整个图形进行检查。
检查细节:
先将所有点分为两个部分,一个是在对称轴左边的,一个是在对称轴右边的。在对称轴上的点可以直接进行计数。
然后检查每一对对应的对称轴两边的点所连成的线段是否被对称轴垂直平分。在这之前还要先判断一下移动之后会交叉的情况:如果有一对点对中,分类属于对称轴左边的当前不在左边,分类属于对称轴右边的当前不在右边,那么无论怎么移动都会产生交叉。这个可以先判断掉。然后还要判断点对中两个点都位于对称轴上的情况,这样的话只移动一个点肯定会出现重合。
#include<bits/stdc++.h>
#define ll long long
#define eps 1e-8
using namespace std;
int sgn(double x){
if(-eps<x&&x<eps)return 0;
if(x<=-eps)return -1;
return 1;
}
int n;
struct point{
double x,y;
point(){}
point(double X,double Y){x=X;y=Y;}
point operator-(point A){
return point(x-A.x,y-A.y);
}
point operator+(point A){
return point(x+A.x,y+A.y);
}
point operator/(double xx){
return point(x/xx,y/xx);
}
void print(){
printf("%.5f %.5f\n",x,y);
}
}p[1004];
double cross(point A,point B){
return A.x*B.y-A.y*B.x;
}
double dot(point A,point B){
return A.x*B.x+A.y*B.y;
}
double dis_t(point A,point B){
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}
int oner(int x){
if(x>n)x-=n;
if(x<=0)x+=n;
return x;
}
struct line{
point s,e;
int ps,pe;
line(){}
line(int x,int y){
ps=x;pe=y;
s=p[x];e=p[y];
}
};
bool parallel(point A,point B){
return (sgn(cross(A,B))==0);
}
bool inMid(line le,point po){
return (sgn(dis_t(po,le.s)-dis_t(po,le.e))==0);
}
point pl[1004],pr[1004];
bool check(int L,int R){
int cnt=0;
line now=line(L,R);
point mid=(p[L]+p[R])/2.0;
point dir=point((now.e.y-now.s.y),-(now.e.x-now.s.x));
int num=1;
pl[1]=p[L];
pr[1]=p[R];
for(int st=L,ed=R;;st=oner(st+1),ed=oner(ed-1)){
if(st!=ed){
if(st!=L&&ed!=R){
num++;
pl[num]=p[st];
pr[num]=p[ed];
//cout<<"-- "<<st<<" "<<ed<<endl;
}
}
else{
if(!inMid(now,p[st]))++cnt;
break;
}
if(oner(st+1)==ed)break;
}
for(int st=L,ed=R;;st=oner(st-1),ed=oner(ed+1)){
if(st!=ed){
if(st!=L&&ed!=R){
num++;
pl[num]=p[st];
pr[num]=p[ed];
//cout<<"-- "<<st<<" "<<ed<<endl;
}
}
else{
if(!inMid(now,p[st]))++cnt;
break;
}
if(oner(st-1)==ed)break;
}
for(int i=1;i<=num;i++){
if(sgn(cross(dir,pl[1]-mid))!=sgn(cross(dir,pl[i]-mid))&&
sgn(cross(dir,pr[1]-mid))!=sgn(cross(dir,pr[i]-mid)))return 0;
}
for(int i=1;i<=num;i++){
point nmid=(pl[i]+pr[i])/2.0;
point dir2=point(nmid.x-mid.x,nmid.y-mid.y);
if(!parallel(dir,dir2)){
if((!inMid(now,pl[i]))||(!inMid(now,pr[i])))++cnt;
else return 0;
}
else{
if(sgn(dis_t(now.s,pl[i])-dis_t(now.e,pr[i]))!=0)++cnt;
}
}
return cnt<=1;
}
int w33ha(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
if(n<=4){
return puts("Y"),0;
}
for(int i=1;i<=n;i++){
int nt=oner(i+1);
if(check(i,nt))return puts("Y"),0;
nt=oner(nt+1);
if(check(i,nt))return puts("Y"),0;
}
puts("N");
return 0;
}
int main(){
int T;scanf("%d",&T);
while(T--)w33ha();
return 0;
}