【计几】曼哈顿距离与切比雪夫距离题集


P3964 [TJOI2013]松鼠聚会

思路:

坐标由 Q Q Q 转化为 M M M 后,问题可转化为,找到一个 k ∈ [ 1 , n ] k∈[1,n] k[1,n] 使得 s u m k = ∑ i = 1 n ∣ x i − x k ∣ + ∑ i = 1 n ∣ y i − y k ∣ sum_k=\sum_{i=1}^n{|x_i-x_k|}+\sum_{i=1}^n{|y_i-y_k|} sumk=i=1nxixk+i=1nyiyk 最小。

然后可以排序+前缀和+二分。

tips: P Q P_Q PQ 转化为 P M P_M PM 时,要除以2,会出现分数。因此我们最后对答案除以2即可,因为根据距离 Q Q Q 的距离公式发现,距离与坐标的关系是线性的。 M M M 距离同理。

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

#define abs(x) (((x)<0)?-(x):(x))

const int N=1e5+10;
typedef long long LL;

int x[N],y[N];
int bx[N],by[N];
LL sumx[N],sumy[N];


int main()
{
    int n, xx, yy; scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d %d",&xx, &yy);
        x[i] = bx[i] = xx + yy; y[i] = by[i] = xx - yy;
    }
    sort(bx + 1, bx + n + 1);
    sort(by + 1, by + n + 1);
    
    for(int i=1; i<=n; i++) sumx[i] = sumx[i - 1] + bx[i], sumy[i] = sumy[i - 1] + by[i];

    LL ans = 1e18;

    for(int i=1; i<=n; i++)
    {
        LL idx = lower_bound(bx + 1, bx + 1 + n, x[i]) - bx;
        LL sum = (idx - 1) * x[i] - sumx[idx - 1] + sumx[n] - sumx[idx] - (n - idx) * x[i];

        idx = lower_bound(by + 1, by + 1 + n, y[i]) - by;
        sum += (idx - 1) * y[i] - sumy[idx - 1] + sumy[n] - sumy[idx] - (n - idx) * y[i];

        ans = min(ans, sum);
    }

    printf("%lld",ans/2);

    system("pause");
    return 0;
}

AT3557 Four Coloring

思路:见洛谷题解,写的很好

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;


const int N=1e7+10;
typedef long long LL;

char col[2][2] = {'R','Y','G','B'};

int main()
{
    int h, w, d; cin>>h>>w>>d;

    for(int i=1; i<=h; i++)
        for(int j=1; j<=w; j++)
        {
            int x = i + j, y = i - j + max(h, w);
            printf("%c",col[(x / d) & 1][(y / d) & 1]);
            if(j == w) printf("\n");
        }

    system("pause");
    return 0;
}

【多维曼哈顿最远点对】poj 2926 Requirements

题意:求五维曼哈顿距离最远点对。

题解:POJ 2926 题解

思路:

  • 对于二维

a n s = m a x ( m a x { ( x + y ) − ( x j + y j ) ( x − y ) − ( x j − y j ) ( − x + y ) − ( − x j + y j ) ( − x − y ) − ( − x j − y j ) } , m a x ( . . . . . . ) , . . . . . . ) (2) ans=max(max\left\{\begin{matrix}(x+y)-(x_j+y_j)\\(x-y)-(x_j-y_j)\\(-x+y)-(-x_j+y_j)\\(-x-y)-(-x_j-y_j)\end{matrix}\right\} \tag{2},max(......),......) ans=max(max(x+y)(xj+yj)(xy)(xjyj)(x+y)(xj+yj)(xy)(xjyj),max(......),......)(2)

  • 也就是在四个状态下维护最大最小值,最后从四个状态中更新即可。

  • 五维也同理。

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;

const int N=1e5+10;
typedef long long LL;

double mi[1 << 5], ma[1 << 5];

int main()
{
    int n; scanf("%d", &n);
    if(n == 1) { cout<<0; return 0; }
    for(int i=0; i< 1<<5; i++) mi[i] = 9e18, ma[i] = -9e18;
    while(n--)
    {
        double a, b, c, d, e; scanf("%lf %lf %lf %lf %lf", &a, &b, &c, &d, &e);
        for(int i=0; i< 1<<5; i++)
        {
            double sum = ((i & 1) ? a : -a) + ((i >> 1 & 1) ? b : -b) + ((i >> 2 & 1) ? c : -c) + ((i >> 3 & 1) ? d : -d) + ((i >> 4 & 1) ? e : -e);
            mi[i] = min(mi[i], sum);
            ma[i] = max(ma[i], sum);
        }
    }
    double ans = 0;
    for(int i=0; i< 1<<5; i++) ans = max(ans, ma[i] - mi[i]);

    printf("%.2f", ans);

    return 0;
}

【多维曼哈顿最近点对】2019牛客第八场多校 D_Distance 三维BIT

题目:https://blog.csdn.net/weixin_42757232/article/details/99306935

题解:- https://blog.csdn.net/weixin_42757232/article/details/99306935

思路:

  • 对于二维:

  • 我们用以前的思路发现,查询时ans为
    a n s = m i n ( m a x { ( x + y ) − ( x j + y j ) ( x − y ) − ( x j − y j ) ( − x + y ) − ( − x j + y j ) ( − x − y ) − ( − x j − y j ) } , m a x ( . . . . . . ) , . . . . . . ) (2) ans=min(max\left\{\begin{matrix}(x+y)-(x_j+y_j)\\ (x-y)-(x_j-y_j)\\ (-x+y)-(-x_j+y_j)\\ (-x-y)-(-x_j-y_j) \end{matrix} \right\} \tag{2} ,max(......),...... ) ans=min(max(x+y)(xj+yj)(xy)(xjyj)(x+y)(xj+yj)(xy)(xjyj,max(......),......)(2)

  • 这样的式子,max没发现以前那样拆开,难以往下推。

  • 如果像以前描的话,我们算出来的是每一行的max然后取min,不能保证和此式子等价。

正解:

  • 以查询点为原点,将空间分隔为八个卦限,最优解一定存在于某个卦限。我们可以以这个立体空间的8个角分别为原点坐标建立8个三维树状数组,树状数组维护前缀最大值。那么我们如果要得到最近的点,我们就去八个树状数组中查询小于等于当前值的最大值,做差取最小值即可。

代码(拍了3000次):

#include<iostream>
#include<cstdio>
using namespace std;

const int N=1e7+100;
typedef long long LL;

int h1, h2, h3;
const int inf = 1e9;

int lowbit(int x) { return x & -x; }
int gethash(int x, int y, int z) { return (2 * h2 + 2) * (2 * h3 + 2) * x + (2 * h3 + 2) * y + z; } // 数据强制hash

struct node{
    int ma[N];
    void init(){
        for(int i=0; i<N; i++) ma[i] = -inf;
    }
    int query(int x, int y, int z){
        int res = -inf;
        for(int i=x; i>=1; i-=lowbit(i))
            for(int j=y; j>=1; j-=lowbit(j))
                for(int k=z; k>=1; k-=lowbit(k))
                    res = max(res, ma[gethash(i, j, k)]);
        return res;
    }
    void modify(int x, int y, int z){
        for(int i=x; i<2 * h1 + 3; i+=lowbit(i))
            for(int j=y; j< 2 * h2 + 3; j+=lowbit(j))
                for(int k=z; k< 2 * h3 + 3; k+=lowbit(k))
                    ma[gethash(i, j, k)] = max(ma[gethash(i, j, k)], x + y + z);
    }
}BIT[8];

int main()
{
    int n; scanf("%d %d %d %d",&h1, &h2, &h3, &n);
    int op, x, y, z;
    for(int i=0; i<8; i++) BIT[i].init();
    while(n--)
    {
        scanf("%d %d %d %d", &op, &x, &y, &z);
        if(op == 1){
            for(int i=0; i< 1 << 3; i++)
            {
                int xx = h1 + 1 + ((i & 1) ? x : -x), yy = h2 + 1 + ((i >> 1 & 1) ? y : -y), zz = h3 + 1 + ((i >> 2 & 1) ? z : -z);
                BIT[i].modify(xx, yy, zz);
            }
        }else{
            int ans = inf;
            for(int i=0; i< 1 << 3; i++)
            {
                int xx = h1 + 1 + ((i & 1) ? x : -x), yy = h2 + 1 + ((i >> 1 & 1) ? y : -y), zz = h3 + 1 + ((i >> 2 & 1) ? z : -z);
                int sum = xx + yy + zz;
                int res = BIT[i].query(xx, yy, zz);
                ans = min(sum - res, ans);
            }
            printf("%d\n", ans);
        }
    }

    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值