判断是否为轴对称图形
问题描述:按一种顺/逆时针顺序给出平面N个点的坐标,判断这N个点所形成的图形是否轴对称。为了简化题目,本题两点所构成的线段均平行于坐标轴
题目链接:https://vjudge.net/problem/FZU-2035
目前的想法是将所有的点都保存到vector中,取第[i]个和第[i+N/2]个点连线,然后取遍所有j可能的检查[i+j]和[i-j]这两个点的中点是否在第[i]和第[i+N/2]点的连线上,如果是轴对称图形的话,那么一定存在一条对角的连线,使得所有其它点关于这条连线对称。
但是编写了程序提交总是通不过,可能数据不够强。现在的程序考虑了可能出现数据中的点不是多边形顶点的情况,例如(0,0),(1,0),(3,0)的情况已经进行了处理。
用C++编写了Point和Line类,主要用于维护对于点与直线的位置关系以及运算。如果万一有哪个公式出了小差错,就会无法通过,这也不知道是思路有问题还是某函数的哪部分出错。有机会再细查查。
现在使用的一组测试数据:
3 4 0 0 0 1 1 1 1 0 6 0 0 4 0 4 2 1 2 1 4 0 4 11 4 0 4 3 5 3 5 5 3 5 3 4 0 4 0 0 1 0 2 0 3 0
程序如下
#include <cstdio>
#include <vector>
using std::vector;
#include <cmath>
int __NaN=0xFFC00000;
const float NaN=*((float *)&__NaN);
int gcd(int x,int y)
{
if(x%y==0)
{
return y;
}
else
{
return gcd(y,x%y);
}
}
class Point{
private:
double X,Y;
bool valid;
public:
Point(){}
Point(bool v)
{
valid = v;
}
Point(double x,double y)
{
X=x;Y=y;
valid=true;
}
bool isValid()
{return valid;}
double getX()
{
if(valid)
return X;
else
return NaN;
}
double getY()
{
if(valid)
return Y;
else
return NaN;
}
Point midPoint(Point p);
};
Point Point::midPoint(Point p)
{
if(valid && p.isValid())
return Point((X+p.getX())/2,(Y+p.getY())/2);
else
return Point(false);
}
class Line{
private:
double A,B,C;
public:
Line(){}
Line(double a,double b,double c)
{
A=a;
B=b;
C=c;
}
Line(Point a,Point b)
{
double dx = a.getX()-b.getX();
double dy = a.getY()-b.getY();
A=dy;
B=-1.0*dx;
C=dx*a.getY()-dy*a.getX();
}
void output()
{
printf("%.1fx%+.1fy%+.1f=0\n",A,B,C);
}
double dist(Point a);
Point CrossPoint(Line b);
bool inLine(Point p);
};
double Line::dist(Point a)
{
return (A*a.getX()+B*a.getY()+C)/sqrt(A*A+B*B);
}
Point Line::CrossPoint(Line L)
{
double tx,ty;
if(A*L.A*B*L.B ==0)
{
if((A==0 && L.A==0) || (B==0 && L.B==0))
{
return Point(false);
}
else
{
if(A==0)
{
ty = -1*C/B;
tx = -1*(L.B*ty+L.C)/L.A;
}
else if(L.A==0)
{
ty = -1*L.C/L.B;
tx= -1*(B*ty+C)/A;
}
else if(B==0)
{
tx = -1*C/A;
ty = -1*(L.C+L.A*tx)/L.B;
}
else //L.B==0
{
tx = -1*L.C/L.A;
ty = -1*(C+A*tx)/B;
}
return Point(tx,ty);
}
}
else if((A-L.A)*(B-L.B)==0)
{
// assume there no 2 same lines;
if(A-L.A==0)
{
ty=(C-L.C)/(L.B-B);
tx = -1*(B*ty+C)/A;
}
else // B-L.B==0
{
tx = (C-L.C)/(L.A-A);
ty = -1*(C+A*tx)/B;
}
return Point(tx,ty);
}
else
{
double D=L.A*B-A*L.B, D1 = L.A*C+A*L.C;
ty = -D1/D; // assume there no parallel lines
tx = -1*(B*ty+C)/A;
return Point(tx,ty);
}
}
bool Line::inLine(Point p)
{
const double epsilon = 0.00000001;
return fabs(A*p.getX()+B*p.getY()+C)<epsilon;
}
void solve()
{
vector<Point> v;
int i,N,x,y;
scanf("%d",&N);
for(i=0;i<N;i++)
{
scanf("%d%d",&x,&y);
v.push_back(Point(x,y));
}
for(i=0;i<N+2;i++)
{
Line L0 = Line(v[i%v.size()],v[(i+2)%v.size()]);
if(L0.inLine(v[(i+1)%v.size()]))
{
v.erase(v.begin()+(i+1)%v.size());
i-=1;
}
}
int RealPoints = v.size();
int winFlag = 0;
for(i=0;i<RealPoints/2 && winFlag==0;i++)
{
winFlag=1;
Line L0 = Line(v[i],v[i+RealPoints/2]);
for(int j=1;j<RealPoints/2 && winFlag==1;j++)
{
Point r = v[(i+j)%RealPoints].midPoint(v[(i+RealPoints-j)%RealPoints]);
if(L0.inLine(r)==false)
{
winFlag = 0;
break;
}
}
if(winFlag==1)
{
break;
}
}
if(winFlag==1)
printf("YES\n");
else
printf("NO\n");
return ;
}
int main(void)
{
int T;
scanf("%d",&T);
for(int i = 0 ;i<T;i++)
{
printf("Case %d: ",i+1);
solve();
}
return 0;
}