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;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Spring.NET学习笔记一。
    Spring.NET学习笔记三(log4net的配置)
    C# 中virtual,override,new 的区别与用法(转载)
    java中的输入输出(转载)
    C# checked与unchecked用法
    C# string学习(转载)
    C# TextBox中的Validating与Validated事件
    java代理模式 (转)
    Jquery好友选择器
    回溯与递归
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF575E.html
Copyright © 2011-2022 走看看