• [USACO12FEB]Symmetry


    传送门:

    https://www.luogu.com.cn/problem/P3046

    https://ac.nowcoder.com/acm/contest/6306/G

    题意

    给定n个不同的点,求这个点集有多少条对称轴

    题解

    对于一个点只有两种情况,一种是和另一个点关于这条线对称,一种是在对称轴上。

    第一种情况:随机选择一个点p,枚举其他的点和他形成的对称轴,然后再判断这个对称轴是不是点集的对称轴。

    第二种情况:当点在对称轴上时,要么另一个点 q 也在对称轴上,两点所在的直线是对称轴,这种情况直接判断这个对称轴是不是点集的对称轴。要么另一个点 q 关于这个点 p 所在的直线有对称点,这个时候按照第一种情况随机点为 q ,枚举其他点和他形成的对称轴,但是这个对称轴要经过点 p 。

    想法很好理解,但是实现很难,在洛谷看到了一个题解,代码比较容易理解。

    https://www.luogu.com.cn/blog/jzzcjb/dui-cheng-xing-symmetry-ti-xie

    用到的数学结论

    两点(x1,y1)(x2,y2)求过两点直线Ax+By+C=0
      A=y2-y1 B=x1-x2 C=x2*y1-x1*y2 
      
    两点(x1,y1)(x2,y2)求两点间的对称轴Ax+By+C=0
      A=x1-x2 B=y1-y2 C=-((x1+x2)(x1-x2)+(y1+y2)(y1-y2))/2
      
    求(x',y')关于直线 Ax+By+C=0 的对称点(x0,y0) 
      设 k=-2*(A*x'+B*y'+C)/(A*A+B*B);
      x0=x'+k*A; 
      y0=y'+k*B;

    代码

    优化了一下这个题解的代码,可以直接用set来记录一对点是否存在

     1 #include<bits/stdc++.h>
     2 #define eps 1e-6
     3 using namespace std;
     4 
     5 int n,cnt,x[100100],y[100100];
     6 set<pair<int,int> >s;
     7 
     8 bool dy(double x,double y){return ((x-y<=eps)||(y-x<=eps));}
     9 
    10 bool is(double A,double B,double C){//判断某条直线是否是对称轴
    11     for(int i=1;i<=n;i++){
    12         /*
    13             求(x',y')关于直线 Ax+By+C=0 的对称点(x0,y0)
    14             设 k=-2*(A*x'+B*y'+C)/(A*A+B*B);
    15             x0=x'+k*A;
    16             y0=y'+k*B;
    17         */
    18         double k=-2*(double)(A*x[i]+B*y[i]+C)/(A*A+B*B);
    19         double xo=x[i]+k*A;int xx=round(xo);
    20         double yo=y[i]+k*B;int yy=round(yo);
    21         if(!s.count({xx,yy})) return 0;
    22     }
    23     return 1;
    24 }
    25 
    26 bool check(int a,int b){ //以两点为一对对称点
    27     //A=x1-x2 B=y1-y2 C=-((x1+x2)(x1-x2)+(y1+y2)(y1-y2))/2
    28     double A=x[a]-x[b];
    29     double B=y[a]-y[b];
    30     double C=(double)-((x[a]*x[a]-x[b]*x[b])+(y[a]*y[a]-y[b]*y[b]))/2;
    31     if(a!=1&&A*x[1]+B*y[1]+C!=0) return 0;
    32     return is(A,B,C);
    33 }
    34 
    35 bool ok(int a,int b){ //以两点所在直线为对称轴
    36     //A=y2-y1 B=x1-x2 C=x2*y1-x1*y2
    37     int A=y[b]-y[a];
    38     int B=x[a]-x[b];
    39     int C=x[b]*y[a]-x[a]*y[b];
    40     return is(A,B,C);
    41 }
    42 
    43 int main()
    44 {
    45     cin>>n;
    46     for(int i=1;i<=n;i++) cin>>x[i]>>y[i],s.insert({x[i],y[i]});
    47     for(int i=2;i<=n;i++) cnt+=check(1,i);
    48     for(int i=2;i<n;i++) cnt+=check(i,n);
    49     cout<<cnt+ok(1,n);
    50 }
  • 相关阅读:
    Oracle适配问题解决
    Oracle12C创建视图权限不足
    Oracle12C配置对外访问
    Oracle12C创建scott账户
    Oracle12C安装配置文档
    Redis适配采坑记
    Redis安装问题解决方案
    Redis Linux 安装部署
    【计网 第四章-2】
    【信息论编码2】测度论
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/13501435.html
Copyright © 2020-2023  润新知