[HDU Multi-School Fourth Scene 2019][HDU 6617][D. Enveloping Convex]

Keywords: PHP

Title link: http://acm.hdu.edu.cn/showproblem.php?pid=6617

Main idea of the topic: Give a convex hull \(P\), find the smallest polygon that is similar to \(P\) and parallel to its corresponding edge, so that \(m\) points \(q_i\) given by the topic are all contained by the polygon, and output the smallest similarity ratio

Question: The dichotomous answer \(k\), consider how to determine if \(P\) can be enlarged \(k\) times so that they can all be inside a polygon by shifting the \(m\) points.If all edges of a polygon are treated as directed segments (counterclockwise), then \(m\) points are inside the polygon if and only if they are on the left side of these directed segments.For the edge record \(f_i\) of section \, it means that i f the point \(q_{f_i}\) is on the left side of this edge, all points are guaranteed to be on the left side of it. After calculating the convex hull for the \(m\) point, the \(f_i\) can be found within the time complexity of \(m)\.So all we need to know is i f there is a vector to shift so that after these \(m\) points have been shifted, all the points \(f_i\) are on the left side of article \(i).

So if we find the qualified set of vectors \(\vec{A_i}\) for each edge \((p_i,p_{i+1})\), we can judge whether the current scale \(k\) is legal by determining whether their intersection is empty.You can find that \(\vec{A_i}=\{\vec{OA}|A\text{is on the left of}\vec{(p_i-q_{f_i}, p_{i+1}-q_{f_i})}\}\) represents a half plane, so we can solve this problem by finding the intersection of half planes.

Note that the title requires parallel edges, so we will also rotate the original graph \(180^{\circ}\) once more to get the minimum output of the answer twice.

#include<bits/stdc++.h>
using namespace std;
#define N 100001
const double eps=1e-10;
int sgn(double x)
{
    if(x<-eps)return -1;
    if(x>eps)return 1;
    return 0;
}
struct Point
{
    double x,y;
    void read(){scanf("%lf%lf",&x,&y);}
    Point operator +(const Point &t)const{return {x+t.x,y+t.y};}
    Point operator -(const Point &t)const{return {x-t.x,y-t.y};}
    double operator *(const Point &t)const{return x*t.y-y*t.x;}
    Point operator *(const double t)const{return {x*t,y*t};}
    Point operator /(const double t)const{return {x/t,y/t};}
    double ang()const{return atan2(1.0*y,1.0*x);}
    double length()const{return sqrt(x*x+y*y);}
}p[N];
struct Line
{
    Point p1,p2;
    Point isct(const Line &t)const
      {
      double a=(p2-p1)*(t.p1-p1);
      double b=(p2-p1)*(p1-t.p2);
      return (t.p1*b+t.p2*a)/(a+b);
      }
}q[N],line[N];
Point cent;
bool cmpang(const Point &p1,const Point &p2)
{
    int tmp=sgn((p1-cent).ang()-(p2-cent).ang());
    if(tmp!=0)return tmp<0;
    return (p1-cent).length()<(p2-cent).length();
}
struct Polygon
{
    int n;
    Point a[N];
    void read()
      {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)
        a[i].read();
      }
    void ChangetoConvex()
      {
      for(int i=2;i<=n;i++)
        if(a[i].x<a[1].x || (a[i].x==a[1].x && a[i].y<a[1].y))
          swap(a[1],a[i]);
      cent=a[1];
      sort(a+2,a+n+1,cmpang);
      int top=2;
      for(int i=3;i<=n;i++)
        {
        while(top>=2 && (a[top]-a[top-1])*(a[i]-a[top])<=0)top--;
        a[++top]=a[i];
        }
      n=top;
      }
}P,Q;
int T,nxt[N],pre[N],f[N];
bool check(int i,Point A,Point B)
{
    return sgn((B-A)*(Q.a[pre[i]]-Q.a[i]))>=0 && sgn((B-A)*(Q.a[nxt[i]]-Q.a[i]))>=0;
}
bool Left(const Point &p,const Line &l){return sgn((l.p2-l.p1)*(p-l.p1))==1;}
bool HalfPlane(int n)
{
    int h=1,t=1;
    q[1]=line[1];
    for(int i=2;i<=n;i++)
      {
      while(h<t && !Left(p[t-1],line[i]))t--;
      while(h<t && !Left(p[h],line[i]))h++;
      if(sgn((q[t].p2-q[t].p1)*(line[i].p2-line[i].p1))==0)
        q[t]=Left(q[t].p1,line[i])?q[t]:line[i];
      else q[++t]=line[i];
      if(h<t)p[t-1]=q[t].isct(q[t-1]);
      }
    while(h<t && !Left(p[t-1],q[h]))t--;
    if(t-h<=1)return false;
    p[t]=q[t].isct(q[h]);
    double ans=0;
    for(int i=h;i<=t;i++)
      ans+=p[i]*p[(i+1-h)%(t-h+1)+h];
    return sgn(ans)>=0;
}
bool check(double k)
{
    for(int i=1;i<=P.n;i++)
      line[i]={P.a[i]*k-Q.a[f[i]],P.a[i%P.n+1]*k-Q.a[f[i]]};
    return HalfPlane(P.n);
}
double solve()
{
    int j=1;
    for(int i=1;i<=P.n;i++)
      {
      while(!check(j,P.a[i],P.a[i%P.n+1]))j=nxt[j];
      f[i]=j;
      }
    double l=0,r=1e9,mid;
    while(l+eps<r)
      {
      mid=(l+r)*0.5;
      if(check(mid))r=mid;
      else l=mid;
      }
    return l;
}
void init()
{
    double ans=1e18;
    P.read(),Q.read();
    if(Q.n==1){printf("%.6f\n",0.0);return;}
    P.ChangetoConvex();
    Q.ChangetoConvex();
    for(int i=1;i<=Q.n;i++)
      nxt[i]=i%Q.n+1,pre[i%Q.n+1]=i;
    ans=min(ans,solve());
    for(int i=1;i<=P.n;i++)
      P.a[i]=P.a[i]*(-1.0);
    ans=min(ans,solve());
    printf("%.6f\n",ans);
}
int main()
{
    scanf("%d",&T);
    while(T--)init();
}

 

The instructions for \vec{A_i}\: Note about \\vec{A_i}\\\\\\vec {OA}\\OA}\\\\vec {OA}\\\ (\\vec {OA OA}\\\Q, left of p_{i+1}-Q)}.So the origin \(O\) is on the left side of the directed segment \(\vec{p_i, p_{i+1})}\) after shifting \(vec{OQ}\).And \(O+\vec{OA}+\vec{OQ}=O+\vec{OQ}+\vec{OA}=Q+\vec{OA}\so (Q\) is shifted \(\vec{OA}\) to meet the requirements.

Posted by Eddie Fisher on Sun, 04 Aug 2019 12:47:04 -0700