袭击

这道题目的解法是在计算距离时,如果是同一类点就认为距离时无穷大

但是这样的话就会存在一个问题,如果我们递归到某一层的时候,得到的最小距离还是无穷大,那么此时我们再执行原来的算法,时间复杂度就会变成\(O(n^2)\)

即使我们使用一般的算法(就是普通的平面最近点对),然后把

for(int i=1;i<cnt;i++)
	for(int j=i+1;j<=cnt&&(temp[j].y-temp[i].y)*(temp[j].y-temp[i].y)<d;j++)//最多只有6个点
	d=min(d,dis(temp[i],temp[j]));

改成

for(int i=1;i<cnt;i++)
	for(int j=i+1;j<=cnt&&temp[j].y-temp[i].y<d;j++)
	if(temp[i].id^temp[j].id==1) d=min(d,dis(temp[i],temp[j]));

也不行

首先一种hack数据就是同一个地方可能有多个重合的点,此时我们有一个很好的解决方法,对同一类型的点,在相同位置的只保留一个就行了,这里用hash即可

另一种hack数据就是最开始提到的情况,比如这道题目的最后一个数据,所有点都分布在\(y\)轴上,然后前半部分(按照纵坐标排序)全部是第一类点,后半部分全部是第二类点,这样的话时间复杂度就变成了\(O(n^2)\);本来想到的一种解决方法是判断递归树上某一点是否只有一种点,如果是这种情况直接返回,但是这种处理方法也存在一种问题,如果这一点的左半部分和右半部分只有一种点,但是两个部分的点的种类不同,此时你会发现没办法做了;题解区有一个随机化的算法,可以学一下,确定性算法目前还没有想到

确定性的大致代码见下

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
map<pair<ll,ll>,bool> h;
int n;
struct Node
{
	ll x,y;
	int id;
}temp[N],w[N],s1[N],s2[N];
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-48;s=getchar();}
    return x*f;
}
bool cmp(Node i,Node j)
{
	if(i.x==j.x) return i.y<j.y;
	return i.x<j.x;
}
double dis(Node i,Node j)
{
	return sqrt((i.x-j.x)*(i.x-j.x)+(i.y-j.y)*(i.y-j.y));
}
double cal(int l,int r)
{
	if(l==r) return 10000000000;
	bool flag=0;
	for(int i=l+1;i<=r;i++)
	if(w[i].id!=w[l].id)
	{
	    flag=1;
	    break;
	}
	if(!flag) return 10000000000;
	int mid=l+r>>1,cnt=0,tot=0;
	double d1=cal(l,mid),d2=cal(mid+1,r);
	if(d1==10000000000&&d2==10000000000)
	{
		
	}
	double d=min(d1,d2);
	int i=l,j=mid+1;
	while(i<=mid||j<=r)
	{
		while(i<=mid&&abs(w[i].x-w[mid].x)>=d)//先筛选出在虚线框中的点 
		i++;
		while(j<=r&&abs(w[j].x-w[mid].x)>=d) 
		j++;
		if(i<=mid)
		{
			if(j<=r)
			{
				if(w[i].y<w[j].y) temp[++cnt]=w[i++];//仍然按照y坐标升序
				else temp[++cnt]=w[j++];
			}
			else temp[++cnt]=w[i++];
		}
		else if(j<=r) temp[++cnt]=w[j++];
	}
	for(int i=1;i<cnt;i++)
	for(int j=i+1;j<=cnt&&temp[j].y-temp[i].y<d;j++)
	if(temp[i].id^temp[j].id==1) d=min(d,dis(temp[i],temp[j]));
	i=l,j=mid+1;
	int k=l;
	while(i<=mid&&j<=r)//归并排序
	{
		if(w[i].y<w[j].y) temp[k++]=w[i++];
		else temp[k++]=w[j++];
	}
	while(i<=mid) temp[k++]=w[i++];
	while(j<=r) temp[k++]=w[j++];
	for(int i=l;i<=r;i++)
	w[i]=temp[i];
	return d;
}
int main()
{
	int t=read();
	while(t--)
	{
	    n=read();
	    int cnt=0;
	    for(int i=1;i<=n;i++)
	    {
	        ll x=read(),y=read();
	        if(h.find(make_pair(x,y))!=h.end()) continue;
	        h[make_pair(x,y)]=1;
	        w[++cnt].x=x,w[cnt].y=y,w[cnt].id=0;
	    }
	    h.clear();
	    for(int i=1;i<=n;i++)
	    {
	        ll x=read(),y=read();
	        if(h.find(make_pair(x,y))!=h.end()) continue;
	        h[make_pair(x,y)]=1;
	        w[++cnt].x=x,w[cnt].y=y,w[cnt].id=1;
	    }
	    sort(w+1,w+cnt+1,cmp);
	    printf("%.3lf\n",cal(1,cnt));
	}
    return 0;
}
posted @ 2023-12-06 23:01  最爱丁珰  阅读(61)  评论(0编辑  收藏  举报