zoukankan      html  css  js  c++  java
  • bzoj 1185 [HNOI2007]最小矩形覆盖——旋转卡壳

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1185

    矩形一定贴着凸包的一条边。不过只是感觉这样。

    枚举一条边,对面的点就是正常的旋转卡壳。两边的那个点可以用点积的最小/大来判断,因为是投影。

    然后调了一万年。不过好像把精度设成 1e-13 而不是 1e-8 就能过了。

    和许多代码对拍,有各种各样的不同。也不知道自己是不是真的对了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define db double
    using namespace std;
    const int N=5e4+5;const db eps=1e-13,INF=1e18;
    int n,tot; db ans;
    struct Node{
      db x,y;
      Node(db a=0,db b=0):x(a),y(b) {}
      bool operator< (const Node &b)const {return x<b.x||(x==b.x&&y<b.y);}
      Node operator- (const Node &b)const {return Node(x-b.x,y-b.y);}
      Node operator+ (const Node &b)const {return Node(x+b.x,y+b.y);}
      db operator* (const Node &b)const {return x*b.x+y*b.y;}
      Node operator* (const db &b)const {return Node(x*b,y*b);}
      Node operator/ (const db &b)const {return Node(x/b,y/b);}
    }t[N],a[N],prn[5];
    db Mx(db a,db b){return a>b?a:b;}
    int dcmp(db x){if(x>eps)return 1;if(x<-eps)return -1;return 0;}
    db cross(Node u,Node v){return u.x*v.y-u.y*v.x;}
    void upd(int &x){x>n?x-=n:0;}
    db Sqr(db x){return x*x;}
    db dist(Node u,Node v){return sqrt(Sqr(u.x-v.x)+Sqr(u.y-v.y));}
    int main()
    {
      scanf("%d",&tot);
      for(int i=1;i<=tot;i++)scanf("%lf%lf",&t[i].x,&t[i].y);
      sort(t+1,t+tot+1);
      for(int i=1;i<=tot;i++)
        {while(n>1&&dcmp(cross(a[n]-t[i],a[n-1]-t[i]))>=0)n--;a[++n]=t[i];}
      for(int i=tot-1,lm=n;i;i--)
        {while(n>lm&&dcmp(cross(a[n]-t[i],a[n-1]-t[i]))>=0)n--;a[++n]=t[i];}
      a[n]=a[1]; n--; ans=INF;
      int p0=2,cr=2,p1=3;//out of for()
      for(int i=1;i<=n;i++)
        {
          Node d=a[i+1]-a[i];
          while(dcmp(cross(d,a[cr+1]-a[i])-cross(d,a[cr]-a[i]))>0)cr++,upd(cr);
          while(dcmp((a[p0+1]-a[i])*d-(a[p0]-a[i])*d)>=0)p0++,upd(p0);//>=?
          if(i==1)p1=cr;//
          while(dcmp((a[p1+1]-a[i])*d-(a[p1]-a[i])*d)<=0)p1++,upd(p1);
    
          db len=dist(a[i+1],a[i]);
          db s1=(a[p0]-a[i])*d/len, s2=(a[p1]-a[i])*d/len;
          db hi=cross(d,a[cr]-a[i])/len, ara=(s1-s2)*hi;//not /(2*len)
          if(dcmp(ara-ans)>=0)continue; ans=ara;
          //      if(ara>=ans)continue; ans=ara;
          Node x1=d/len*(s1-s2);
          Node x2=d/len*hi; swap(x2.x,x2.y); x2.x=-x2.x;//*i
          prn[1]=a[i]+d/len*s2;  prn[2]=prn[1]+x1;
          prn[3]=prn[2]+x2; prn[4]=prn[1]+x2;
        }
      printf("%.5f
    ",ans);int id=1;
      for(int i=2;i<=4;i++)
        {
          Node u=prn[i],v=prn[id];
          if(dcmp(u.y-v.y)<0||(!dcmp(u.y-v.y)&&dcmp(u.x-v.x)<0))id=i;
        }
      for(int j=1;j<=4;j++,id++,id>4?id=1:0)
        {
          if(!dcmp(prn[id].x))prn[id].x=0;
          if(!dcmp(prn[id].y))prn[id].y=0;//avoid -0
          printf("%.5f %.5f
    ",prn[id].x,prn[id].y);
        }
      return 0;
    }
  • 相关阅读:
    C++头文件保护符和变量的声明定义
    ReactNavtive框架教程(2)
    扩展方法使用
    华为0基础——(练习用)挑7
    HTTP Status 500
    屏蔽DataGridView控件DataError 事件提示的异常信息
    POJ 3630 Phone List Trie题解
    【学习总结】数学-向量叉积
    9.1-9.30推荐文章汇总
    Autolayout环境设置任意个数相等间距排列的按钮的方法
  • 原文地址:https://www.cnblogs.com/Narh/p/10151784.html
Copyright © 2011-2022 走看看