2019杭电多校第五场08
平面上给定一个简单多边形,问最多移动一个点能否使这个多边形对称。要求最终图形是简单多边形。
细节需要注意。一个是简单多边形判断的时候所有点需要在对称轴同一侧。一个是可能的对称轴不只有原多边形相对的两个点或边,或者说对称轴可能被移动。
#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db PI=acos(-1);
const db eps=1e-8, inf=1e12;
bool eq(db x){return fabs(x)<eps;}
int sgn(db x){
if (x<=-eps) return -1;
return x>=eps;
}
#define Vec const vec &
#define Point const point &
struct vec{
db x,y;
vec():x(0),y(0){}
vec(db x, db y):x(x),y(y){} //[i] init-list is easier to use in c++1x
vec(db theta):x(cos(theta)),y(sin(theta)){}
bool operator==(Vec v) const{return eq(x-v.x) && eq(y-v.y);}
db ang() const{return atan2(y,x);}
vec operator+(Vec v) const{return vec(x+v.x,y+v.y);}
vec operator-(Vec v) const{return vec(x-v.x,y-v.y);}
vec operator*(db a) const{return vec(x*a,y*a);}
vec operator/(db a) const{return vec(x/a,y/a);}
db operator|(Vec v) const{return x*v.x+y*v.y;} //dot
db operator&(Vec v) const{return x*v.y-y*v.x;} //cross
db operator!() const{return sqrt(x*x+y*y);} //len
bool operator<(Vec v) const{return x==v.x?y<v.y:x<v.x;}
vec std() const{return *this/!*this;}
vec rot(db rad) const{return vec(x*cos(rad)-y*sin(rad), x*sin(rad)+y*cos(rad));}
vec l90() const{return vec(-y,x);}
vec r90() const{return vec(y,-x);}
vec vert() const{return (*this).l90().std();} //l90 and standard
void rd(){scanf("%lf%lf",&x,&y);}
void prt(){printf("%f %f\n",x,y);}
friend ostream& operator<<(ostream &o, Vec v){return o<<v.x<<','<<v.y;}
}p[2010];
typedef vec point;
//point projection on line A+tV
point lineProj(Point p, Point s, Vec v){
return s+v*(v|p-s)/(v|v);
}
//symmetric point of P about line A+tV
point symmetric(Point p, Point s, Vec v){
return lineProj(p,s,v)*2-p;
}
db cross(Point a, Point b, Point c){return b-a & c-a;}
bool onLine(Point p, Point a, Point b){return eq(p-a&b-a);}
int main(){
int T; cin>>T;
while (T--){
int n; cin>>n;
for (int i=0;i<n;i++) p[i].rd();
if (n==3){
puts("Y");
continue;
}
db area=0;
for (int i=2;i<n;i++){
area+=cross(p[0],p[i-1],p[i]);
}
if (area<0) reverse(p,p+n);
for (int i=0;i<n;i++) p[i+n]=p[i];
if (n&1){
int i;
for (i=0;i<n;i++){
int des=i+n/2;
point p1=(p[des]+p[des+1])/2;
point v1=p1-p[i];
int cnt=0,j;
for (j=1;j<=n/2;j++){
if (cross(p[i],p1,p[i+j])>-eps && cross(p[i],p1,p[(i-j+n)%n]<eps)) break;
if (!(symmetric(p[i+j],p[i],v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2+1){
puts("Y");
break;
}
p1=(p[(i-1+n)%n]+p[i+1])/2;
v1=(p[i+1]-p1).vert();
cnt=1;
if (!onLine(p[i],p1,p1+v1)){
for (j=2;j<=n/2;j++){
if (cross(p[i],p1,p[i+j])>-eps && cross(p[i],p1,p[(i-j+n)%n]<eps)) break;
if (!(symmetric(p[i+j],p1,v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2+1){
puts("Y");
break;
}
}
}
if (i==n) puts("N");
}
else{
int i;
for (i=0;i<n/2;i++){
int des=i+n/2;
point v1=p[des]-p[i];
int cnt=0,j;
for (j=1;j<n/2;j++){
if (cross(p[i],p[des],p[i+j])>-eps && cross(p[i],p[des],p[(i-j+n)%n])<eps) break;
if (!(symmetric(p[i+j],p[i],v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2){
puts("Y");
break;
}
vec p1=(p[(i-1+n)%n]+p[i+1])/2;
v1=(p[i+1]-p1).vert();
cnt=1;
if (onLine(p[i],p1,p1+v1) || onLine(p[des],p1,p1+v1)){
for (j=2;j<n/2;j++){
if (cross(p[i],p1,p[i+j])>-eps && cross(p[i],p1,p[(i-j+n)%n]<eps)) break;
if (!(symmetric(p[i+j],p1,v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2){
puts("Y");
break;
}
}
}
if (i==n/2){
for (i=0;i<n/2;i++){
int des=i+n/2;
point p0=(p[i+1]+p[i])/2;
vec v1=(p[i+des+1]+p[i+des])/2;
int cnt=0,j;
for (j=0;j<n/2;j++){
if (cross(p0,p0+v1,p[i+1+j])>-eps && cross(p0,p0+v1,p[(i-j+n)%n])<eps) break;
if (!(symmetric(p[i+1+j],p0,v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2){
puts("Y");
break;
}
v1=(p[i+1]-p[i]).vert();
cnt=0;
for (j=1;j<n/2;j++){
if (cross(p0,p0+v1,p[i+1+j])>-eps && cross(p0,p0+v1,p[(i-j+n)%n])<eps) break;
if (!(symmetric(p[i+1+j],p0,v1)==p[(i-j+n)%n]))
cnt++;
if (cnt>1) break;
}
if (j==n/2){
puts("Y");
break;
}
}
if (i==n/2) puts("N");
}
}
}
return 0;
}