IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 平面最短曼哈顿距离技巧 Dist Max、Lena and Matrix、Gojou and Matrix Game 三题题解 -> 正文阅读

[数据结构与算法]平面最短曼哈顿距离技巧 Dist Max、Lena and Matrix、Gojou and Matrix Game 三题题解

曼哈顿距离

曼哈顿距离是指对于两个点 a ( i , j ) , b ( i ′ , j ′ ) a(i,j),b(i',j') a(i,j),b(i,j),它们的曼哈顿距离是 ∣ i ? i ′ ∣ + ∣ j ? j ′ ∣ |i-i'|+|j-j'| i?i+j?j,记为 d i s ( a , b ) dis(a,b) dis(a,b)

我们显然可以做如下变化

d i s ( a , b ) = ∣ i ? i ′ ∣ + ∣ j ? j ′ ∣ = max ? ( i ? i ′ , i ′ ? i ) + max ? ( j ? j ′ . j ′ ? j ) dis(a,b)=|i-i'|+|j-j'|=\max(i-i',i'-i)+\max(j-j'.j'-j) dis(a,b)=i?i+j?j=max(i?i,i?i)+max(j?j.j?j)

这是因为 a b s abs abs函数的性质,两个数一非正一非负,就相当于取 max ? \max max

两个最大值,做笛卡尔积一共可以产生四种情况,加号可以直接拆开,得到

d i s ( a , b ) = max ? ( i ? i ′ + j ? j ′ , i ? i ′ + j ′ ? j , i ′ ? i + j ? j ′ , i ′ ? i + j ′ ? j ) = max ? ( ( i + j ) ? ( i ′ + j ′ ) , ( i ? j ) ? ( i ? j ′ ) , ? ( i ? j ) + ( i ′ ? j ′ ) , ? ( i + j ) + ( i ′ + j ′ ) ) = max ? ( ∣ ( i + j ) ? ( i ′ + j ′ ) ∣ , ∣ ( i ? j ) ? ( i ? j ′ ) ∣ ) \begin{aligned} dis(a,b) &= \max(i-i'+j-j',i-i'+j'-j,i'-i+j-j',i'-i+j'-j)\\ &= \max((i+j)-(i'+j'),(i-j)-(i-j'),-(i-j)+(i'-j'),-(i+j)+(i'+j'))\\ &=\max(|(i+j)-(i'+j')|,|(i-j)-(i-j')|)\\ \end{aligned} dis(a,b)?=max(i?i+j?j,i?i+j?j,i?i+j?j,i?i+j?j)=max((i+j)?(i+j),(i?j)?(i?j),?(i?j)+(i?j),?(i+j)+(i+j))=max((i+j)?(i+j),(i?j)?(i?j))?

之后我们可以令 z a = i + j , w z = i ? j , z b = i ′ + j ′ , w b = i ′ ? j ′ z_a=i+j,w_z=i-j,z_b=i'+j',w_b=i'-j' za?=i+j,wz?=i?j,zb?=i+j,wb?=i?j,那么可以进一步化简为

d i s ( a , b ) = m a x ( ∣ z a ? z b ∣ , ∣ w a ? w b ∣ ) dis(a,b)=max(|z_a-z_b|,|w_a-w_b|) dis(a,b)=max(za??zb?,wa??wb?)

这就是一个另外表述的曼哈顿距离了。

平面最远曼哈顿距离

有什么用呢,比如我们要求一个点和一个点集的最大距离,那么相当于求 max ? ( max ? ( ∣ z i ? z x ∣ , ∣ w i ? w x ∣ ) ) {\max}(\max(|z_i-z_x|,|w_i-w_x|)) max(max(zi??zx?,wi??wx?))。绝对值函数是很容易处理的,我们只需维护z的最大值最小值和w的最大值最小值就行了,那么最后答案应该是 m a x ( z m a x ? z x , z x ? z m i n , w m a x ? w x , w x ? w m i n ) max(z_{max}-z_x,z_x-z_{min},w_{max}-w_x,w_x-w_{min}) max(zmax??zx?,zx??zmin?,wmax??wx?,wx??wmin?)。扫一遍的复杂度是 O ( n ) O(n) O(n),假如拓展到点集和点集的最远距离或是最小最大距离等等,我们就只用维护一个枚举一个就好了,时间复杂度为 O ( n ) O(n) O(n)。对于我们的标题“平面最远曼哈顿”,就扫一遍维护,在扫一遍枚举就行了。

一些例题

DIST Max(平面最远曼哈顿距离)

E - Dist Max (atcoder.jp)

思路

裸题,上面提到流程了。

代码

// ___________.__             _________                                   __   
// \__    ___/|  |__   ____  /   _____/__ __  ____   ____________   _____/  |_ 
//   |    |   |  |  \_/ __ \ \_____  \|  |  \/    \ /  ___/\____ \ /  _ \   __\
//   |    |   |   Y  \  ___/ /        \  |  /   |  \\___ \ |  |_> >  <_> )  |  
//   |____|   |___|  /\___  >_______  /____/|___|  /____  >|   __/ \____/|__|  
//                 \/     \/        \/           \/     \/ |__|                 
#include<cstdio>
#include<iostream>
#include<set>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#include<bitset>
#include<functional>
#include<cassert>
#include<complex>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#ifdef THESUNSPOT
    #define de(i) cout<<#i<<": "<<i<<endl;
#else
    #define de(i) ;
#endif
#define int long long
//#define double long double
using namespace std;
    typedef long long ll;
    const int maxn=1000005;
    const int inf=0x3f3f3f3f3f3f3f3f;
    int n,m,k;
    void yes(){
        cout<<"YES"<<endl;
    }
    void no(){
        cout<<"NO"<<endl;
    }

    void solve(){
        cin>>n;
        int maxz=-inf,minz=inf,maxw=-inf,minw=inf;
        while(n--){
            int x,y;
            cin>>x>>y;
            maxz=max(maxz,x+y);
            minz=min(minz,x+y);
            maxw=max(maxw,x-y);
            minw=min(minw,x-y);
        }
        cout<<max(abs(maxz-minz),abs(maxw-minw))<<endl;
    }

    signed main(){
        IOS
        #ifdef THESUNSPOT
            auto st=clock();
            freopen("IO\\in.txt","r",stdin);
            freopen("IO\\out.txt","w",stdout);
        #endif

        int tn=1;
        while(tn--){
            solve();
        }
        #ifdef THESUNSPOT
            auto ed=clock();
            cout<<endl<<"time: "<<ed-st<<"ms."<<endl;
            srand(time(0));
            cout<<"version: "<<rand()%1000<<endl;
        #endif
    }		
    

Lena and Matrix(最大距离最小化)

Problem - D - Codeforces

思路

也是上面的思路,求一个位置,使得其到所有黑点最大距离最小,我们枚举位置,之后最大距离取min即可。

代码

// ___________.__             _________                                   __   
// \__    ___/|  |__   ____  /   _____/__ __  ____   ____________   _____/  |_ 
//   |    |   |  |  \_/ __ \ \_____  \|  |  \/    \ /  ___/\____ \ /  _ \   __\
//   |    |   |   Y  \  ___/ /        \  |  /   |  \\___ \ |  |_> >  <_> )  |  
//   |____|   |___|  /\___  >_______  /____/|___|  /____  >|   __/ \____/|__|  
//                 \/     \/        \/           \/     \/ |__|                 
#include<cstdio>
#include<iostream>
#include<set>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#include<bitset>
#include<functional>
#include<cassert>
#include<complex>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#ifdef THESUNSPOT
    #define de(i) cout<<#i<<": "<<i<<endl;
#else
    #define de(i) ;
#endif
//#define double long double
using namespace std;
    typedef long long ll;
    const int maxn=1025;
    const int inf=0x3f3f3f3f;
    int n,m,k;
    int a[maxn][maxn];
    void solve(){
        cin>>n>>m;
        pair<int,int>ans;
        int mina=inf;
        string s;
        int zmax=-inf,zmin=inf;
        int wmax=-inf,wmin=inf;
        for(int i=1;i<=n;i++){
            cin>>s;
            for(int j=1;j<=m;j++){
                if(s[j-1]=='B'){
                    a[i][j]=1;
                    zmax=max(zmax,i+j);
                    zmin=min(zmin,i+j);
                    wmax=max(wmax,i-j);
                    wmin=min(wmin,i-j);
                }
                else{
                    a[i][j]=0;
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int mm=-inf;
                int zz=i+j;
                int ww=i-j;
                mm=max({zmax-zz,zz-zmin,wmax-ww,ww-wmin});
                if(mm<mina){
                   // cout<<i<<' '<<j<<endl;
                   // cout<<mm<<endl;
                    mina=mm;
                    ans={i,j};
                }
            }
        }

        cout<<ans.first<<' '<<ans.second<<endl;
    }

    signed main(){
        IOS
        #ifdef THESUNSPOT
            auto st=clock();
            freopen("IO\\in.txt","r",stdin);
            freopen("IO\\out.txt","w",stdout);
        #endif

        int tn=1;
        cin>>tn;
        while(tn--){
            solve();
        }
        #ifdef THESUNSPOT
            auto ed=clock();
            cout<<endl<<"time: "<<ed-st<<"ms."<<endl;
            srand(time(0));
            cout<<"version: "<<rand()%1000<<endl;
        #endif
    }

Gojou and Matrix Game(简单博弈,最大距离)

Problem - E - Codeforces

思路

题意是,给一个n*n方阵,其权值各不同,每次落子可以获得权,每次落子不能放在上一次曼哈顿距离k以内,但是再往前就没有限制了。

轮流落子,输出任意位置i,j,先手胜利或是失败。

容易发现,先手落完子后,假如后手不能一步走到权更高的地方,一定是先手胜利,因为先手可以下回原地。

假如后手移动到了权更高的地方,则相当于颠倒了先手后手,可以相当于在那个权更高的地方继续行动。

基于我们上面说的,我们可以使用递推,先考虑权最大的,之后权小的就可以根据之前推出的大权的胜负来决定小权的正负。

倒推时考虑,假如当前位置能前往其他先手必胜态(注意移动后先后手转置),那么这个点就是必负态。因此我们在倒推时记录必胜态的状态,能到达,也就是要求存在一个必胜态,其距离大于k。反过来说,如果这个点到所有必胜态的距离全小于等于k,那么这个点一定也是必胜态。

到此一切都明朗了,我们只需要倒推维护上面提到的四个量,之后每次判断是否当前点到点集最大曼哈顿距离小于等于k即可。

代码

// ___________.__             _________                                   __   
// \__    ___/|  |__   ____  /   _____/__ __  ____   ____________   _____/  |_ 
//   |    |   |  |  \_/ __ \ \_____  \|  |  \/    \ /  ___/\____ \ /  _ \   __\
//   |    |   |   Y  \  ___/ /        \  |  /   |  \\___ \ |  |_> >  <_> )  |  
//   |____|   |___|  /\___  >_______  /____/|___|  /____  >|   __/ \____/|__|  
//                 \/     \/        \/           \/     \/ |__|                 
#include<cstdio>
#include<iostream>
#include<set>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#include<bitset>
#include<functional>
#include<cassert>
#include<complex>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#ifdef THESUNSPOT
    #define de(i) cout<<#i<<": "<<i<<endl;
#else
    #define de(i) ;
#endif
#define int long long
//#define double long double
using namespace std;
    typedef long long ll;
    const int maxn=4000005;
    const int inf=0x3f3f3f3f3f3f3f3f;
    int n,m,k;
    void yes(){
        cout<<"YES"<<endl;
    }
    void no(){
        cout<<"NO"<<endl;
    }
    pair<int,int>p[maxn];
    void solve(){

        cin>>n>>k;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                int t;
                cin>>t;
                p[t]={i,j};
            }
        }
        vector<string>ans(n+1,string(n,'G'));
        int zmax=-inf,zmin=inf,wmax=-inf,wmin=inf;
        for(int i=n*n;i;i--){
            int x=p[i].first,y=p[i].second;
            int zo=x+y,wo=x-y;
            if(i==n*n||max({zmax-zo,zo-zmin,wmax-wo,wo-wmin})<=k){
                ans[x-1][y-1]='M';
                zmax=max(zmax,x+y);
                zmin=min(zmin,x+y);
                wmax=max(wmax,x-y);
                wmin=min(wmin,x-y);
            }
        }
        for(int i=0;i<n;i++)   cout<<ans[i]<<endl;
    }

    signed main(){
        IOS
        #ifdef THESUNSPOT
            auto st=clock();
            freopen("IO\\in.txt","r",stdin);
            freopen("IO\\out.txt","w",stdout);
        #endif

        int tn=1;
        while(tn--){
            solve();
        }
        #ifdef THESUNSPOT
            auto ed=clock();
            cout<<endl<<"time: "<<ed-st<<"ms."<<endl;
            srand(time(0));
            cout<<"version: "<<rand()%1000<<endl;
        #endif
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-18 23:32:11  更:2022-06-18 23:32:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:38:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码