【bzoj1604】【Usaco2008 Open】Cow Neighborhoods (set+曼哈顿距离性质+并查集)奶牛的邻居

本文介绍了一种使用曼哈顿距离特性及Set数据结构解决特定问题的方法。通过坐标转换,利用Set维护可能相邻的点,实现了快速查找与合并同一区域内的点,适用于算法竞赛中的相似题目。

题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1604
题解:
首先要做这道题我们知道曼哈顿距离的一个性质,那就是:
如果原来坐标是(x, y),令新的坐标为(X, Y), 其中X = x + y, Y = x - y
曼哈顿距离 = |x1 - x2| + |y1 - y2| = max ( |X1 - X2|, |Y1 - Y2| );
还有就是如何运用set,这个百度里可以搜到,看这个东西大概可以知道set怎么用
http://baike.baidu.com/link?url=uVFabYTc3qYwwhKfxKuS-vfAFSKYQquK8iEq4vVrRXyFDm8Ps9oH_GADc6Lfs40cTLfbjfXhnMVLRL-NtnnN4q
接下来就是这道题的关键点,如何判断哪些点在同一个块中:
首先我们将给出的每个点的坐标用(x+y , x-y)来表示,这样的话按新的x坐标从小到大排序,维护一个队列满足队首到队尾的X坐标(X=x+y)距离小于c,这样的话 max ( |X1 - X2|, |Y1 - Y2| ) 中 |X1 - X2| 就满足小于c了,如何满足 |Y1 - Y2| 也小于c呢,我们需要用到平衡树即set,如果新加入元素在set中的前驱后继与它的Y值差值不超过c,则用并查集将他们连在一起,set本身有好多用法,可以参照上面给出的网页。
代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<set>
using namespace std;
typedef long long ll;
const ll inf=1e16;
struct node{
    ll x;ll y;int id;
}a[100005];
int c,n,fa[100005],cnt[100005];
multiset<node>s;
node jia(ll xx,ll yy,int idd)
{
    node tmp;
    tmp.x=xx;tmp.y=yy;tmp.id=idd;
    return tmp;
}
int cmp(node x,node y)
{
    if (x.x!=y.x)
    return x.x<y.x;
    return x.y<y.y;
}
bool operator < (const node a, const node b)
{
    return a.y < b.y;
}
int find(int x)
{
    if (fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
int num;
void unio(int x,int y)
{
    //cout<<x<<' '<<y<<endl;
    int X=find(x);
    int Y=find(y);
    if (X!=Y)
    {
        fa[X]=Y;
        num--;
    }
}
int main()
{
    scanf("%d%d",&n,&c);num=n;
    for (int i=1;i<=n;i++)
    {
        ll x,y;
        fa[i]=i;
        scanf("%lld%lld",&x,&y);
        a[i].x=x+y;a[i].y=x-y;
        a[i].id=i;
    }
    sort(a+1,a+1+n,cmp);
    s.insert(jia(0,inf,0));
    s.insert(jia(0,-inf,0));
    s.insert(a[1]);
    int head=1;
    node l,r;
    for (int i=2;i<=n;i++)
    {
        while(a[i].x-a[head].x>c)
        {
            s.erase(s.find(a[head]));
            head++;
        }
        set <node> ::iterator it=s.lower_bound(a[i]);
        r=*it;it--;l=*it;
        if (a[i].y-l.y<=c)
        unio(a[i].id,l.id);
        if (r.y-a[i].y<=c)
        unio(a[i].id,r.id);
        s.insert(a[i]);
    }
    int sum=-1;
    for (int i=1;i<=n;i++)
    {
        int tmp=find(i);
        cnt[tmp]++;
        sum=max(sum,cnt[tmp]);
    }
    printf("%d %d\n",num,sum);
}
提供的引用内容未提及曼哈顿距离转化的方法和原理。曼哈顿距离本身是一种用于测量两个点在多维空间中的距离距离度量方法,得名于曼哈顿的街区布局,交叉点的距离通常通过水平和垂直路线测量[^1]。 一般而言,曼哈顿距离在二维空间中,对于两点 \(P_1(x_1,y_1)\) 和 \(P_2(x_2,y_2)\),其计算公式为 \(d = |x_1 - x_2|+|y_1 - y_2|\)。在多维空间中,若有两点 \(A=(a_1,a_2,\cdots,a_n)\) 和 \(B=(b_1,b_2,\cdots,b_n)\)曼哈顿距离 \(d=\sum_{i = 1}^{n}|a_i - b_i|\) 。 对于曼哈顿距离的转化,从原理上可能是为了适应特定的应用场景或算法需求。例如在某些机器学习算法中,可能需要将曼哈顿距离转化为一种更易于计算或比较的形式。一种常见的转化方式是归一化,原理是将距离值映射到一个特定的区间,如 \([0,1]\) ,方法可以使用最小 - 最大归一化,公式为 \(d_{normalized}=\frac{d - d_{min}}{d_{max}-d_{min}}\) ,其中 \(d\) 是原始的曼哈顿距离,\(d_{min}\) 和 \(d_{max}\) 分别是数据集中曼哈顿距离的最小值和最大值。 ```python import numpy as np def manhattan_distance(point1, point2): return np.sum(np.abs(np.array(point1) - np.array(point2))) def min_max_normalization(distance, min_distance, max_distance): return (distance - min_distance) / (max_distance - min_distance) # 示例数据 point_a = [1, 2, 3] point_b = [4, 5, 6] # 计算曼哈顿距离 distance = manhattan_distance(point_a, point_b) # 假设已知最小和最大距离 min_dist = 0 max_dist = 10 # 归一化曼哈顿距离 normalized_distance = min_max_normalization(distance, min_dist, max_dist) print("原始曼哈顿距离:", distance) print("归一化后的曼哈顿距离:", normalized_distance) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值