多个点求曼哈顿距离最大值的优化、二分查找将优化问题转化为判定问题、曼哈顿距离的另一种形式(适用于多次查询某点与多个点的曼哈顿距离的最大值)

对于曼哈顿距离存在另一种形式的计算:

 

等式右边两项分别对应于:x1和x2、y1和y2的大小关系相同和不同的情况。

这样做的好处是,对于多个(x2,y2)点,可以预处理出全部点的最大和最小的x2+y2、x2-y2,这样对于任意其他点,可以在O(1)计算出它和全部点的曼哈顿距离的最大值。

 例题:

https://codingcompetitions.withgoogle.com/kickstart/round/00000000008f4a94/0000000000b55465#analysis

注意此题的优化思想,利用二分查找,将优化问题转化为判定某值是否可行。

代码:

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int grid[300][300];

void YD()
{
    int r, c;
    cin >> r >> c;
    string str;
    for (int i = 1; i <= r; i++)
    {
        cin >> str;
        for (int j = 1; j <= c; j++)
        {
            grid[i][j] = str[j - 1] - '0';
        }
    }
    deque<pair<int, int>> que;
    for (int i = 1; i <= r; i++)
    {
        for (int j = 1; j <= c; j++)
        {
            if (grid[i][j]) grid[i][j] = 0, que.push_back({ i,j });
            else grid[i][j] = 1e8;
        }
    }
    while (que.size())
    {
        auto[x, y] = que.front();
        que.pop_front();
        int dis = grid[x][y];
        if (x + 1 <= r && grid[x + 1][y] > dis + 1)
        {
            grid[x + 1][y] = dis + 1;
            que.push_back({ x + 1,y });
        }
        if (y + 1 <= c && grid[x][y + 1] > dis + 1)
        {
            grid[x][y + 1] = dis + 1;
            que.push_back({ x ,y + 1 });
        }
        if (x - 1 > 0 && grid[x - 1][y] > dis + 1)
        {
            grid[x - 1][y] = dis + 1;
            que.push_back({ x - 1,y });
        }
        if (y - 1 > 0 && grid[x][y - 1] > dis + 1)
        {
            grid[x][y - 1] = dis + 1;
            que.push_back({ x ,y - 1 });
        }
    }

    int max_dis = 0;
    for (int i = 1; i <= r; i++)
    {
        for (int j = 1; j <= c; j++)
            max_dis = max(max_dis, grid[i][j]);
    }


    int l = 0, rr = max_dis;
    while (l < rr)
    {
        int mid = (l + rr) / 2;
        int add_max = -1e9, sub_max = -1e9;
        int add_min = 1e9, sub_min = 1e9;
        for (int i = 1; i <= r; i++)
        {
            for (int j = 1; j <= c; j++)
            {
                if (grid[i][j] > mid)
                {
                    add_max = max(add_max, i + j);
                    sub_max = max(sub_max, i - j);
                    add_min = min(add_min, i + j);
                    sub_min = min(sub_min, i - j);
                }
            }
        }
        bool flag = false;

        for (int i = 1; i <= r; i++)
        {
            for (int j = 1; j <= c; j++)
            {
                if (grid[i][j]!=0)
                {
                    int max_dist = max({ abs(i + j - add_max), abs(i + j - add_min),
                                    abs(i - j - sub_max), abs(i - j - sub_min) });
                    if (max_dist <= mid)
                    {
                        flag = true;
                    }
                }
            }
        }
        if (flag)
        {
            rr = mid;
        }
        else
        {
            l = mid + 1;
        }

    }

    cout << l << endl;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T = 1;
    cin >> T;
    for (int i = 1; i <= T; i++)
    {
        cout << "Case #" << i << ": ";
        YD();
    }
    return 0;
}
View Code
复制代码

 

posted @   80k  阅读(399)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示