Luogu2647

前言

其实这题做法蛮多,本质就是P1429P1452的结合。

两题都可以乱搞,因此我们谈一谈如何乱搞过这题

最正规的做法是分治,但这需要一定的计算几何技巧

最正规的乱搞做法是KDT,但这只是期望复杂度可行,实际最坏复杂度依旧会挂

因此我们还要发扬人类智慧,了解非常规的乱搞做法——随机化



乱搞做法

Part 1 平面最近点对

先考虑贪心。

我们把下标以 \(x\) 为关键字,从小到大排序(可以使用STL自带的std::pairOI wiki资料),
然后仅计算每个点与下一个点的距离,计入答案。

这显然是个假做法,反例

考虑仅计算每个点与下 \(d\) 个点的距离\(d\) 是一个你自己定的小常数,取 \(5-10\) 即可),计入答案,正确率大大提高(一个小细节:不要自己和自己求距离)。

但如果出题人刻意卡你咋办?

考虑随机化调整数据,譬如每个点绕原点旋转某个相同角度啥的(怎么进行向量旋转?)。

如果不放心,多跑几遍旋转+贪心,正确率更高,但通常没必要。

利用随机化提高贪心正确率,称作随机化贪心算法,简称随贪

随贪习题:

Part 2 平面最远点对(凸包直径)

你依旧可以沿用上题方法,但是 \(d\) 应调到 \(100\) 左右,取 \(\max\)

不过还有一种非常妙的随机化做法,即随机化反复迭代

先随机取一些点(迭代点),求出其与所有点的距离,取最远的更新答案同时以其更新并以此点更新迭代点继续迭代,详见代码。



Code

其实是把两题拼起来的代码,所以有点乱(

带一个double快读模板。

#include <algorithm>
#include <math.h>
#include <random>
#include <stdio.h>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
std::pair<dbl,dbl>P[100000];dbl X[100000],Y[100000];
dbl d(dbl x1,dbl y1,dbl x2,dbl y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
dbl read()
{
    dbl x=0,t=0;int s=0,f=1;chr c;
    do c=getchar();while((c<'0'||c>'9')&&c!='-'&&c!='.');
    if(c=='-')f=-1,c=getchar();
    while(c>='0'&&c<='9'&&c!='.')x=c-'0'+x*10,c=getchar();
    if(c=='.')c=getchar();else return x*f;
    while(c>='0'&&c<='9')t=t*10+c-'0',++s,c=getchar();
    while(s--)t/=10;return(x+t)*f;
}
const dbl alpha=1.14514;
int main()
{
    const dbl SIN=sin(alpha),COS=cos(alpha);
    std::mt19937 rng(19260817);
    uint n,p,q;dbl ans=1145141919810,wil;scanf("%u",&n);
    for(uint i=0;i<n;i++)X[i]=read(),Y[i]=read(),P[i].first=X[i]*COS-Y[i]*SIN,P[i].second=X[i]*SIN+Y[i]*COS;
    std::sort(P,P+n);
    for(uint i=0;i<n;i++)
        for(uint j=1;j<=5&&i+j<n;j++)
            _min(ans,d(P[i].first,P[i].second,P[i+j].first,P[i+j].second));
    printf("%.2lf ",ans);
    for(uint w=0;w<8;w++)
    {
        q=p=rng()%n;
        for(uint t=0;t<5;t++)
        {
            wil=0;
            for(uint i=0;i<n;i++)if(_max(wil,d(X[p],Y[p],X[i],Y[i])))q=i;
            _max(ans,wil);
            p=q;
        }
    }
    printf("%.2lf\n",ans);
	return 0;
}
posted @ 2022-02-14 07:00  myee  阅读(45)  评论(0编辑  收藏  举报