line symmetric
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 (i−1)-th point and the (i+1)-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 T T T indicating the number of tests.
Each test begins with one line containing one integer n n n, denoting the number of points in the polygon. Then, the i-th line in the following n n n lines contains two integers x i , y i , ( x i , y i ) x_i,y_i, (x_i,y_i) xi,yi,(xi,yi) is the coordinate of the i i i-th point. For any 1 ≤ i < n 1\leq i< n 1≤i<n, the i-th point is connected to the ( i + 1 ) (i+1) (i+1)-th point with an edge. Also, the n n n-th point is connected to the first point.
-
1 ≤ T ≤ 40 1\leq T\leq40 1≤T≤40
-
3 ≤ n ≤ 1000 3\leq n\leq 1000 3≤n≤1000
-
coordinates are in the range [ − 1000 , 1000 ] [−1000,1000] [−1000,1000]
Output
For each test, if you can move at most one point making the polygon line-symmetric, print a character ′ Y ′ 'Y' ′Y′ in a line, otherwise print a character ′ N ′ 'N' ′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
Source
2019 Multi-University Training Contest 5
题意
- 就是给你一个简单多边形,问是否可以最多移动一个点的位置【相连的点不变】,使得其成为一个轴对称图形【点也要求对称】
题解
- 显然当 n ≤ 4 n\leq 4 n≤4时一定有解,然后对于 n > 4 n>4 n>4的情况,如果有解,那么一定存在一堆相邻的点对或者间隔一个点的点对是关于某一条对称轴对称的,所以枚举上述两种情况,去 c h e c k check check使剩下的点对一一对称需要修改的点数是否符合要求就行了
- 下面这张图是一组比较难想到的情况,答案是
N
N
N
- 另外附上一组个人认为是比较强的数据,答案是
N
N
N
代码
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
#define pi acos(-1.0)
const double eps=1e-8;
int n;
int sgn(double k)
{
return k<-eps?-1:(k<eps?0:1);
}
double Acos(double a)
{
if(a>=1) return 0;
else if(a<=-1) return pi;
return acos(a);
}
struct point{ //点结构体
double x,y;
point(double a=0,double b=0) {
x=a;y=b;
}
point operator+(point other) {
return point(x+other.x,y+other.y);
}
point operator-(point other) {
return point(x-other.x,y-other.y);
}
point operator*(double k) {
return point(x*k,y*k);
}
point operator/(double k) {
if(k==0) printf("error\n");
return point(x/k,y/k);
}
friend bool operator<(const point &p1,const point &p2) {
if(sgn(p1.x-p2.x)==0) return p1.y<p2.y;
return p1.x<p2.x;
}
friend bool operator==(const point &p1,const point &p2) {
return sgn(p1.x-p2.x)==0&&sgn(p1.y-p2.y)==0;
}
friend bool operator!=(const point &p1,const point &p2) {
return sgn(p1.x-p2.x)!=0||sgn(p1.y-p2.y)!=0;
}
double operator*(point other) { //点乘,即数量积,内积(ABcos<A,B>)
return x*other.x+y*other.y;
}
double cha(point other) { //叉乘,即向量积,外积(ABsin<A,B>)
return x*other.y-y*other.x;
}
friend double angle(point p1,point p2) {
return Acos(p1*p2/len(p1)/len(p2));
}
bool onseg(point p1,point p2) {//判断q是否在线段p1-p2上
point q=*this;
return sgn((p1-q).cha(p2-q))==0&&sgn((p1-q)*(p2-q))<=0;
}
friend double dis(point p1,point p2) { //计算两点距离
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
friend double len2(point p1) {
return p1.x*p1.x+p1.y*p1.y;
}
friend double len(point p1) {
return sqrt(p1.x*p1.x+p1.y*p1.y);
}
friend bool cross(point p1,point p2,point q1,point q2) { //判断线段p1-p2与线段q1-q2有交点,不包括平行和重合
if(parallel(p1,p2,q1,q2)) return false;
point inter=intersect(p1,p2,q1,q2);
if(inter.onseg(p1,p2)&&inter.onseg(q1,q2)) return true;
return false;
}
friend point intersect(point p1,point p2,point q1,point q2) {//计算直线p1-p2是否与直线q1-q2的交点,注意不能平行
return p1+(p2-p1)*((q2-q1).cha(q1-p1)/(q2-q1).cha(p2-p1));
}
friend bool parallel(point p1,point p2,point q1,point q2) { //判断线段p1-p2是否与线段q1-q2平行,重合也会返回true
return sgn((q2-q1).cha(p2-p1))==0;
}
friend bool parallel_intersect(point p1,point p2,point q1,point q2) { //判断线段p1-p2和线段q1-q2在平行的情况下是否重合
return p1.onseg(q1,q2)||p2.onseg(q1,q2)||q1.onseg(p1,p2)||q2.onseg(p1,p2);
}
friend point extend(point p,double len) { //将向量p长度变为len返回一个新的向量,方向不变
if(sgn(dis(point(0,0),p))==0) return point(0,len); //0向量
return point(p*(len/dis(point(0,0),p)));
}
friend double dis_point_line(point a,point b,point c) { //点a到直线b,c的距离
double cos0=(a-b)*(c-b)/(len(a-b)*len(c-b));
return len(a-b)*sin(Acos(cos0));
}
//返回点a在直线p1-p2上的垂足
friend point chuizu(point a,point p1,point p2) {
return p1+(p2-p1)*((p2-p1)*(a-p1))/len2(p2-p1);
}
//返回点a关于直线p1-p2的对称点
friend point duichen(point a,point p1,point p2) {
point q=chuizu(a,p1,p2);
return point(2*q.x-a.x,2*q.y-a.y);
}
friend point rotate(point p1,point p2,double a) {//点p2绕着点p1顺时针方向旋转a角度,a为弧度,返回新的point
point vec=p2-p1;
double xx=vec.x*cos(a)+vec.y*sin(a);
double yy=vec.y*cos(a)-vec.x*sin(a);
return point(p1.x+xx,p1.y+yy);
}
void print() {
printf("x:%.3lf y:%.3lf\n",x,y);
}
}p[maxn],tmp[maxn]; //tmp表示临时用来判断的数组
typedef point Vector;
int check(int prea,int preb,int a,int b,point p1,point p2)
{
if(!parallel(tmp[prea],tmp[a],p1,p2)&&!parallel(tmp[preb],tmp[b],p1,p2)) { //特判第一张图的情况
point k1=intersect(tmp[prea],tmp[a],p1,p2),k2=intersect(tmp[preb],tmp[b],p1,p2);
if(k1.onseg(tmp[prea],tmp[a])&&k2.onseg(tmp[preb],tmp[b])) {
return 2;
}
}
if(sgn(dis_point_line(tmp[a],p1,p2)-dis_point_line(tmp[b],p1,p2))==0){ //到对称轴距离相同
if(sgn((tmp[a]-tmp[b])*(p1-p2))==0) return 0;
else{
tmp[b]=duichen(tmp[a],p1,p2);
return 1;
}
}else {
point duichen_b=duichen(tmp[a],p1,p2); //看把b改成a关于对称轴对称的情况是否符合
if(!cross(tmp[prea],tmp[a],tmp[preb],duichen_b)&&duichen_b!=tmp[a]) {
tmp[b]=duichen_b;
return 1;
}
point duichen_a=duichen(tmp[b],p1,p2);
if(!cross(tmp[prea],duichen_a,tmp[preb],tmp[b])&&duichen_b!=tmp[b]) {
tmp[a]=duichen_a;
return 1;
}
return 2; //都不符合返回false
}
}
bool check1()
{
for(int i=0;i<n;i++) {
int j=(i-1+n)%n,k=(i+1)%n;
point mid=(p[j]+p[k])/2;
point chui=rotate(mid,p[k],3*pi/2);
if(!p[i].onseg(mid,chui)) continue;
int cnt=0;
for(int j=0;j<n;j++) tmp[j]=p[j];
for(j=(j-1+n)%n,k=(k+1)%n;;j=(j-1+n)%n,k=(k+1)%n){
if(k==(j+1)%n) break;
else if(k==j) {
if(sgn(dis_point_line(p[k],mid,chui))!=0) cnt++;
break;
}
cnt+=check((j+1)%n,(k-1+n)%n,j,k,mid,chui);
if(cnt>1) break;
}
if(cnt<=1) return true;
}
return false;
}
bool check2()
{
for(int i=0;i<n;i++) {
int j=i,k=(i+1)%n;
point mid=(p[j]+p[k])/2,chui=rotate(mid,p[k],3*pi/2);
int cnt=0;
for(int j=0;j<n;j++) tmp[j]=p[j];
for(j=(j-1+n)%n,k=(k+1)%n;;j=(j-1+n)%n,k=(k+1)%n) {
if(k==(j+1)%n) break;
else if(k==j) {
if(sgn(dis_point_line(tmp[k],mid,chui))!=0) cnt++;
break;
}
cnt+=check((j+1)%n,(k-1+n)%n,j,k,mid,chui);
if(cnt>1) break;
}
if(cnt<=1) return true;
}
return false;
}
int main()
{
int t;scanf("%d",&t);
while(t--) {
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%lf %lf",&p[i].x,&p[i].y);
if(n<=4) {printf("Y\n");continue;}
if(check1()) printf("Y\n");
else if(check2()) printf("Y\n");
else printf("N\n");
}
}