[HDU6631]line symmetric

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 ( i − 1 ) (i−1) (i1)-th point and the ( i + 1 ) (i+1) (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, denoting the number of points in the polygon. Then, the i i 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-th point. For any 1 ≤ i &lt; n 1≤i&lt;n 1i<n, the i i i-th point is connected to the ( i + 1 ) (i+1) (i+1)-th point with an edge. Also, the n-th point is connected to the first point.

  • 1 ≤ T ≤ 40 1≤T≤40 1T40
  • 3 ≤ n ≤ 1000 3≤n≤1000 3n1000
  • 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’ 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值