zoukankan      html  css  js  c++  java
  • 【CF575E】Spectator Riots(结论题+凸包)

    点此看题面

    • 一张二维平面上,全集为整点集(S={(x,y)|x,yin[1,10^5]})
    • 另有(n)个整点集(P_i=Scap{(x,y)||x-x_i|+|y-y_i|le v_i}),从每个点集中随机选择一个点称作(p_i)
    • 要求从(igcup_{i=1}^nP_i)中选出三个不共线的点,使得它们的外接圆期望覆盖的(p)点最多,若有多种方案则要求外接圆半径最大。
    • (nle10^5,(x_i,y_i)in S)且不全部共线

    结论题+凸包

    仔细想想发现必然存在一种方案能够包含整个(igcup_{i=1}^nP_i),这时候期望包含(p)点数量达到最大。

    因此,我们实际上就是要作出一个半径尽可能大的圆,使得这个圆包含所有给定点。

    然后就有一个结论:这个圆必然经过凸包上三个相邻顶点。(理性的证明不太会,但感性理解应该还是比较容易的)

    所以我们只要求出凸包,之后求每相邻三点的外接圆应该还算是比较简单的,只要求出任意两条中垂线的交点即可。

    要求出整张图的凸包,可以先求出每个点集的凸包,只需考虑当点集越界的时候有些特殊,注意讨论即可。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define V 100000
    #define DB double
    using namespace std;
    int n,cnt;struct P
    {
    	DB x,y;I P(Con DB& a=0,Con DB& b=0):x(a),y(b){}
    	I P operator + (Con P& o) Con {return P(x+o.x,y+o.y);}
    	I P operator - (Con P& o) Con {return P(x-o.x,y-o.y);}
    	I P operator * (Con DB& o) Con {return P(x*o,y*o);}
    	I P operator / (Con DB& o) Con {return P(x/o,y/o);}
    	I DB operator * (Con P& o) Con {return x*o.x+y*o.y;}
    	I DB operator ^ (Con P& o) Con {return x*o.y-y*o.x;}
    	I bool operator < (Con P& o) Con {return x!=o.x?x<o.x:y<o.y;} 
    	I bool operator == (Con P& o) Con {return x==o.x&&y==o.y;} 
    	I DB L() {return sqrt((*this)*(*this));}
    }p[8*N+5];
    int T;P s[8*N+5];I void Get()//求凸包
    {
    	#define pd(A,B,C) (((C-B)^(B-A))>0||(((C-B)^(B-A))==0&&(A<B)==(B<C)))//判断是否需要弹出元素
    	RI i;sort(p+1,p+cnt+1),cnt=unique(p+1,p+cnt+1)-p-1;//排序并去重
    	for(sort(p+1,p+cnt+1),i=1;i<=cnt;s[++T]=p[i++]) W(T>1&&pd(s[T-1],s[T],p[i])) --T;//从左往右求一遍
    	for(i=cnt-1;i;s[++T]=p[i--]) W(T>1&&pd(s[T-1],s[T],p[i])) --T;--T;//从右往左求一遍
    }
    struct S {P A,B;I S(Con P& a=P(),Con P& b=P()):A(a),B(b){}};
    I S MidVer(Con P& A,Con P& B) {P mid=(A+B)/2,t=B-mid;return S(mid,mid+P(t.y,-t.x));}//中垂线
    I DB Calc(Con P& A,Con P& B,Con P& C)//计算外接圆半径
    {
    	S S1=MidVer(A,B),S2=MidVer(A,C);DB w1=(S1.A-S2.A)^(S2.B-S2.A),w2=(S2.B-S2.A)^(S1.B-S2.A);
    	P O=S1.A+(S1.B-S1.A)*w1/(w1+w2);return (A-O).L();//求交点即为外心,计算半径
    }
    int main()
    {
    	RI i,x,y,z;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d%d",&x,&y,&z),//求出每个点集的凸包,需要讨论
    		x+z<=V?p[++cnt]=P(x+z,y):(p[++cnt]=P(V,min(y+z-(V-x),V)),p[++cnt]=P(V,max(y-z+(V-x),0))),
    		y+z<=V?p[++cnt]=P(x,y+z):(p[++cnt]=P(min(x+z-(V-y),V),V),p[++cnt]=P(max(x-z+(V-y),0),V)),
    		x-z>=0?p[++cnt]=P(x-z,y):(p[++cnt]=P(0,min(y+z-x,V)),p[++cnt]=P(0,max(y-z+x,0))),
    		y-z>=0?p[++cnt]=P(x,y-z):(p[++cnt]=P(min(x+z-y,V),0),p[++cnt]=P(max(x-z+y,0),0));
    	RI t;DB f,g=0;for(Get(),s[T+1]=s[1],s[T+2]=s[2],i=1;i<=T;++i) (f=Calc(s[i],s[i+1],s[i+2]))>g&&(g=f,t=i);//枚举相邻三个顶点计算半径
    	return printf("%.0lf %.0lf
    %.0lf %.0lf
    %.0lf %.0lf
    ",s[t].x,s[t].y,s[t+1].x,s[t+1].y,s[t+2].x,s[t+2].y),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    HDU 1501 Zipper(DFS)
    HDU 2181 哈密顿绕行世界问题(DFS)
    HDU 1254 推箱子(BFS)
    HDU 1045 Fire Net (DFS)
    HDU 2212 DFS
    HDU 1241Oil Deposits (DFS)
    HDU 1312 Red and Black (DFS)
    HDU 1010 Tempter of the Bone(DFS+奇偶剪枝)
    HDU 1022 Train Problem I(栈)
    HDU 1008 u Calculate e
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF575E.html
Copyright © 2011-2022 走看看