[SHTSC 2014] 信号增幅仪

最小覆盖圆算法。看着题解半蒙半抄的搞过去了…

主要参考以下
http://blog.csdn.net/acdreamers/article/details/9406735
http://blog.csdn.net/lthyxy/article/details/6661250
http://blog.himdd.com/archives/2666

其中有一个求外心的过程是错的…害我调了好久…还把x和y搞反…可是就算是错的我居然过了80%的数据…

仍然几个疑问:

(1)最小覆盖圆算法时间复杂度的证明

(2)椭圆的中心未定的情况下,为什么以原点为中心旋转&缩放即可?(我几何不好QAQ)

program amplifier;
uses math;
type point=record
             x,y:extended;
           end;
const maxn=50000;
      pi=3.14159265358979;
      eps=0.00000001;
var n,i,p:longint;
    a,r:extended;
    o:point;
    v:array[1..maxn+10] of point;
procedure rotate(i:longint);
var x,y:extended;
begin
  x:=v[i].x*cos(-a)-v[i].y*sin(-a);
  y:=v[i].x*sin(-a)+v[i].y*cos(-a);
  v[i].x:=x/p;
  v[i].y:=y;
end;

function circumcenter(p,q,r:point):point;
var a,b,c,d,e,f:extended;
begin
  a:=q.x-p.x;
  b:=q.y-p.y;
  c:=-(q.x*q.x+q.y*q.y-p.x*p.x-p.y*p.y)/2;
  d:=r.x-p.x;
  e:=r.y-p.y;
  f:=-(r.x*r.x+r.y*r.y-p.x*p.x-p.y*p.y)/2;
  circumcenter.y:=(-c*d+f*a)/(b*d-e*a);
  circumcenter.x:=(-c*e+f*b)/(a*e-b*d);
end;

function dis(a,b:point):extended;
begin
  dis:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
end;

procedure min_cover_circle;
var i,j,k:longint;
begin
  o:=v[1];r:=0;
  for i:=2 to n do
    begin
      if dis(v[i],o)>r+eps then
        begin
          o:=v[i];r:=0;
          for j:=1 to i do
            if dis(v[j],o)>r+eps then
              begin
                o.x:=(v[i].x+v[j].x)/2;
                o.y:=(v[i].y+v[j].y)/2;
                r:=dis(v[j],o);
                for k:=1 to j do
                  if dis(v[k],o)>r+eps then
                    begin
                      o:=circumcenter(v[i],v[j],v[k]);
                      r:=dis(o,v[i]);
                    end;
              end;
        end;
    end;
end;

begin
  //assign(input,‘amplifier20.in‘);reset(input);
  //assign(output,‘amplifier20.out‘);rewrite(output);
  readln(n);
  for i:=1 to n do
    readln(v[i].x,v[i].y);
  readln(a);a:=a/180*pi;
  readln(p);
  for i:=1 to n do
    rotate(i);
  if n=2 then
    begin
      writeln(dis(v[1],v[2])/2:0:3);
      //close(input);close(output);
      halt;
    end;
  min_cover_circle;
  writeln(r:0:3);
  //close(input);close(output);
end.

amplifier

其实说起来也不是很难,增量法我在考场居然也想到了,就是那时没想到可以以原点为中心,算法也写的有问题- -
来一发考场逗比错误代码,有空分析下错哪里了0 0

program amplifier;
uses math;
const pi=3.141592653589;
type vtype=record
             x,y:real;
           end;
var n,p,i,n1,n2,n3:longint;
    xx,yy,xt,yt,a,aa,x0,y0:real;
    v:array[0..50010] of vtype;

procedure cac(x1,y1,x2,y2,x3,y3:real);
var a1,a2,b1,b2,c1,c2:real;
begin
  if x1*y2+x2*y3+x3*y1-x3*y2-x2*y1-x1*y3=0 then exit;
  a1:=2*(x1-x3);b1:=2*p*p*(y1-y3);c1:=(x1*x1-x3*x3)+p*p*(y1*y1-y3*y3);
  a2:=2*(x1-x2);b2:=2*p*p*(y1-y2);c2:=(x1*x1-x2*x2)+p*p*(y1*y1-y2*y2);
  xt:=(b2*c1-b1*c2)/(a1*b2-a2*b1);
  yt:=(a1*c2-a2*c1)/(a1*b2-a2*b1);
  a:=sqrt(sqr(x1-xt)+p*p*sqr(y1-yt));
end;

function ini(t:integer;x0,y0,a:real):boolean;
var tt:real;
begin
  tt:=sqr(v[t].x-x0)+p*p*sqr(v[t].y-y0);
  if tt<=a*a then exit(true) else exit(false);
end;

procedure work2;
begin
  xx:=(v[n1].x+v[n2].x)/2;
  yy:=(v[n1].y+v[n2].y)/2;
  a:=sqrt(sqr(v[n1].x-xx)+p*p*sqr(v[n1].y-yy));
  writeln((a/p):0:3);
end;

function line(n1,n2,n3:integer):boolean;
var x1,x2,x3,y1,y2,y3:real;
begin
  x1:=v[n1].x;x2:=v[n2].x;x3:=v[n3].x;
  y1:=v[n1].y;y2:=v[n2].y;y3:=v[n3].y;
  if x1*y2+x2*y3+x3*y1-x3*y2-x2*y1-x1*y3=0 then exit(true) else exit(False);
end;

procedure workline;
begin
  if ((v[n1].x<v[n2].x) and (v[n2].x<v[n3].x)) or ((v[n3].x<v[n2].x) and (v[n2].x<v[n1].x)) then
    begin
      n2:=n3;n3:=n3+1;exit;
    end;
  if ((v[n2].x<v[n1].x) and (v[n1].x<v[n3].x)) or ((v[n3].x<v[n1].x) and (v[n1].x<v[n2].x)) then
    begin
      n1:=n2;n2:=n3;n3:=n3+1;exit;
    end;
  if ((v[n1].x<v[n3].x) and (v[n3].x<v[n2].x)) or ((v[n2].x<v[n3].x) and (v[n3].x<v[n1].x)) then
    begin
      n3:=n3+1; exit;
    end;
end;

begin
  assign(input,‘amplifier.in‘);reset(input);
  assign(output,‘amplifier.out‘);rewrite(output);
  readln(n);
  for i:=1 to n do
    readln(v[i].x,v[i].y);
  readln(a);readln(p);
  for i:=1 to n do
    begin
      x0:=v[i].x;y0:=v[i].y;
      v[i].x:=cos(-a/180*pi)*x0-sin(-a/180*pi)*y0;
      v[i].y:=sin(-a/180*pi)*x0+cos(-a/180*pi)*y0;
    end;
  v[n+1].x:=200000000;v[n+1].y:=200000001;
  if n=1 then writeln(0);
  if n=2 then
    begin
      n1:=1;n2:=2;
      work2;
    end;
  if n>=3 then
    begin
      n1:=1;n2:=2;n3:=3;
      while (line(n1,n2,n3)) and (n3<>n+1) do workline;
      if n3=n+1 then
        begin
          work2;
          exit;
        end;
      cac(v[n1].x,v[n1].y,v[n2].x,v[n2].y,v[n3].x,v[n3].y);
      xx:=xt;yy:=yt;aa:=a;
      for i:=n3+1 to n do
        begin
          if not ini(i,xx,yy,aa) then
            begin
              cac(v[n1].x,v[n1].y,v[n2].x,v[n2].y,v[i].x,v[i].y);
              if ini(n3,xt,yt,a) then
                begin
                  n3:=i;xx:=xt;yy:=yt;aa:=a;continue;
                end;
              cac(v[n1].x,v[n1].y,v[i].x,v[i].y,v[n3].x,v[n3].y);
              if ini(n2,xt,yt,a) then
                begin
                  n2:=n3;n3:=i;xx:=xt;yy:=yt;aa:=a;continue;
                end;
              cac(v[i].x,v[i].y,v[n2].x,v[n2].y,v[n3].x,v[n3].y);
              if ini(n1,xt,yt,a) then
                begin
                  n1:=n2;n2:=n3;n3:=i;xx:=xt;yy:=yt;aa:=a;continue;
                end;
            end;
        end;
      writeln((a/p):0:3);
    end;
  close(input);close(output);
end.

amplifier-wrong

[SHTSC 2014] 信号增幅仪

时间: 2024-10-06 21:19:35

[SHTSC 2014] 信号增幅仪的相关文章

BZOJ 3564 SHOI 2014 信号增幅仪 坐标变换+最小圆覆盖

题目大意:给出平面上的一些点,现在让你用一个长轴与x轴成一定角度的,长轴:短轴已知的椭圆来覆盖所有的坐标,求最小的短轴长度. 思路:很明显,这个椭圆的形状和放置状态已经给出了,但是没有办法求最小拖圆覆盖啊.采用坐标变换,将椭圆变成圆.首先我们先让长轴与x轴平行,将平面上的所有点都旋转这个角度.之后只需要让所有点的x坐标除以长轴:短轴就可以了.剩下的就是最小圆覆盖了. 注:坐标旋转公式: x' = x * cos(a) - y * sin(a) y' = x * sin(a) + y * cos(

BZOJ3564 [SHOI2014]信号增幅仪

先把椭圆长轴转到x轴上,然后把x轴按照比例缩回去,于是就变成了最小圆覆盖问题,上板子...就行 1 /************************************************************** 2 Problem: 3564 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:256 ms 7 Memory:2380 kb 8 *************************************

bzoj-3564 信号增幅仪

题意: 给出平面上n个点和一个角度α,一个比值p: 求一个长轴与x轴夹角为α,长轴与短轴比值为p的椭圆, 包含了这n个点,且使半短轴最小: 题解: 本来只是上bz找找计算几何凸包啥的裸题刷刷,结果怎么碰上这么一个玄学的玩意... 况且这题还不用凸包: 看起来只是将圆拓展到了椭圆,但是直接按原模型乱搞似乎有些难度: 判断点和椭圆的关系需要一部转化: 两点间求椭圆,甚至三点间求椭圆都并不好搞,而且还有一个旋转的角度要考虑: 所以不能硬上,要转化模型,转化到熟悉的模型就可以搞了嘛: 将圆变成椭圆需要两

[BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】

题目链接:BZOJ - 3564 题目分析 求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值. 那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 x 坐标除以长轴与短轴的比值,然后就直接做最小圆覆盖了. 随机增量法,一定别忘了 random_shuffle . 代码 #include <iostream> #include <cstdlib> #include <cstring> #include <cstd

COGS2642 / Bzoj4590 [Shoi2015]自动刷题机

Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 906  Solved: 321 Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代码. B.心情不好,删掉了之前写的y行代码.(如果y大于当前代码长度则相当于全部删除.) 对于每

bzoj 4590

4590: [Shoi2015]自动刷题机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 860  Solved: 300[Submit][Status][Discuss] Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代码

BZOJ 4590: [Shoi2015]自动刷题机 二分答案

4590: [Shoi2015]自动刷题机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1056  Solved: 380[Submit][Status][Discuss] Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代

BZOJ4590 自动刷题机

SHOI2015 Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代码. B.心情不好,删掉了之前写的y行代码.(如果y大于当前代码长度则相当于全部删除.) 对于每个OJ所有题目,存在某个固定的长度n>0.一旦自动刷题机在某秒结束时积累了大于等于n行的代码,它就会 自动提交并

bzoj4590自动刷题机

传送门 Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代码. B.心情不好,删掉了之前写的y行代码.(如果y大于当前代码长度则相当于全部删除.) 对于每个OJ所有题目,存在某个固定的长度n>0.一旦自动刷题机在某秒结束时积累了大于等于n行的代码,它就会 自动提交并AC此题,