算法:曼哈顿距离转切比雪夫距离+并查集+平衡树
(这里的代码选择STL里的set实现平衡树)
储备知识
曼哈顿距离
在二维空间内,两个点之间的曼哈顿距离为它们横坐标之差的绝对值与纵坐标之差的绝对值之和。设点 A(x1,y1),B(x2,y2),则 A,B 之间的曼哈顿距离用公式可以表示为:
dAB=|x1-x2|+|y1-y2|

通过公式,我们很容易得到 A,B两点间的曼哈顿距离:
dAB=|6-2|+|5-2|=4+3=7
切比雪夫距离
在二维空间内,两个点之间的切比雪夫距离为它们横坐标之差的绝对值与纵坐标之差的绝对值的最大值。设点 A(x1,y1),B(x2,y2),则 A,B 之间的切比雪夫距离用公式可以表示为:
dAB=max(|x1-x2|,|y1-y2|)

通过公式,我们很容易得到 A,B两点间的切比雪夫距离:
dAB=max(|6-2|,|5-2|)=max(4,3)=4
二维曼哈顿距离与切比雪夫距离的相互转化
设A(x1,Y1),B(x2,y2),A,B两点的曼哈顿距离为:
dAB=|x1-x2|+|y1-y2|
=max{x1-x2+y1-y2,x1-x2+y2-y1,x2-x1+y1-y2,x2-x1+y2-y1}
=max{|(x1+y1)-(x2+y2)|,|(x1-y1)-(x2-y2)|}
很容易发现,这就是 (x1 + y1,x1- y1), (x2 + y2,x2 - y2) 两点之间的切比雪夫距离。
这样,我们就把两点间的曼哈顿距离转化成了切比雪夫距离。
set
STL中很重要的一种容器!!!不会的自行百度学习!!!
题目
题面描述
了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.
每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1~109];Xi,Yi∈整数.
当满足下列两个条件之一,两只奶牛i和j是属于同一个群的:
1.两只奶牛的曼哈顿距离不超过C(1≤C≤109),即lXi - Xjl+IYi- Yjl≤C.
2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群.
给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛?
输入
第1行:N和C;
接下来N行:每行输入一只奶牛的坐标.
输出
输出仅一行,先输出牛群数,再输出最大牛群里的牛数,用空格隔开.
解题思路
先将A(x1,Y1),B(x2,y2)两点的曼哈顿距离:|x1-x2|+|y1-y2|按上述知识转化为 (x1 + y1,x1- y1), (x2 + y2,x2 - y2) 两点之间的切比雪夫距离:max{|(x1+y1)-(x2+y2)|,|(x1-y1)-(x2-y2)|}。
设X=x+y,Y=x-y,现在只要保证max{△X,△Y}<C,既保证△X<C且△Y<C即可。
先将转化后的所有点按X排序,维护△X<c,不满足则指针now右移。然后对Y维护平衡树,如果当前点与其前驱后继的△Y<C,则用并查集将它们合并在一起(即放在一个牛群中)。
具体细节请看代码中注释!!!
代码演示
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define inf 10000000000LL
using namespace std;
int n,c,ans,maxn;
int fa[100005],tot[100005];
struct data
{
long long x,y; //x即为思路中的X,y即为思路中的Y
int id;
}a[100005];
multiset <data> b;
set <data>::iterator it;
inline bool operator<(data a,data b) //重载<
{
return a.y<b.y;
}
inline bool cmpx(data a,data b)
{
return a.x<b.x;
}
int read() //快读
{
long long x=0,f=1;
char ch=getchar();
if (ch=='-') f=-1;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9')
{
x=(x*10+ch-'0');
ch=getchar();
}
return x*f;
}
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void un(int x,int y) //并查集合并
{
int p=find(x),q=find(y);
if(p!=q)
{
fa[p]=q;
ans--; //如果两头牛在一个群里,牛群数-1
}
}
int main()
{
n=read();
c=read();
ans=n; //开始设有n个牛群
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++)
{
int t1=read(),t2=read();
a[i].x=t1+t2;
a[i].y=t1-t2; //曼哈顿距离转切比雪夫距离
a[i].id=i;
}
sort(a+1,a+n+1,cmpx); //所有牛按X排序
b.insert((data){0,inf,0});
b.insert((data){0,-inf,0});
int now=1;
b.insert(a[1]);
for(int i=2;i<=n;i++)
{
while(a[i].x-a[now].x>c) //保证同一牛群的牛△X<C,不满足则指针now右移
{
b.erase(b.find(a[now]));
now++;
}
it=b.lower_bound(a[i]);
data r=*it,l=*--it; //找按X排序后当前牛的前驱后继的位置
if(a[i].y-l.y<=c) un(a[i].id,l.id);
if(r.y-a[i].y<=c) un(a[i].id,r.id); //如果前驱(后继)与当前牛的△Y<C
b.insert(a[i]);
}
for(int i=1;i<=n;i++) tot[find(i)]++;
//根节点相同的牛在同一并查集中,统计每个牛群含牛头数
for(int i=1;i<=n;i++) maxn=max(maxn,tot[i]);
printf("%d %d\n",ans,maxn);
return 0;
}
本文介绍了一种将曼哈顿距离转换为切比雪夫距离的算法,并结合并查集和平衡树解决奶牛群划分问题。通过将距离问题转化为切比雪夫距离,利用平衡树维护奶牛位置关系,实现高效计算。

2623

被折叠的 条评论
为什么被折叠?



