1. 程式人生 > >最遠 Manhattan 距離

最遠 Manhattan 距離

hdu 技術 max 來看 acm 最小 tor pac 遠的

最遠 Manhattan 距離

處理問題

K維空間下的n個點,求兩點最遠曼哈頓距離

思路

以二維為例介紹算法思想,即可類推到k維。對於P,Q兩點,曼哈頓距離|Px-Qx|+|Py-Qy|可看作(±Px±Py)-(±Qx±Qy),不難發現Px應該與Qx的符號相同,Py與Qy符號相同,因此共四種情況。這樣寫的好處是,每個點可以表示成相同的形式(±Px±Py)。而曼哈頓距離一定是四種情況中值最大的那種,所以要求兩點最遠曼哈頓距離,可以枚舉所有的取符號情況,對於每種情況,維護出上述表示下n個點的最大值與最小值,求出差值。則最遠的曼哈頓距離一定是所有情況中的最大差值。

代碼描述

ll max_Manhattan(ll p[][10],int n,int k)
{
    ll ans=0;
    for (int s=0;s<(1<<k);++s)
    {
        ll mx=-1e18,mn=1e18;
        for (int i=0;i<n;++i)
        {
            ll tmp=0;
            for (int j=0;j<k;++j)
                tmp+=(s&(1<<j))?p[i][j]:-p[i][j];
            mx=max(mx,tmp),mn=min(mn,tmp);
        }
        ans=max(ans,mx-mn);
    }
    return ans;
}

應用

一般題目可能不會太直白的要求最遠曼哈頓距離,以今年多校的一道題為例,可以HDU上找到J.CSGO.

題目大意:

給n個主武器,m個副武器。每個武器有1個s屬性和k個x屬性。要求選取主副兩把武器,使得技術分享圖片最大。

思路:

現在再來看這道題,可以發現其形式很像求K維下最遠曼哈頓距離。前面多的兩項可以看作第k+1維,為了保證它們的形式是兩項相加,將其中一個武器集合的s屬性都置為負即可。然後就做一次k維下n個點和m個點之間取兩點的最遠曼哈頓距離。要註意,選取的點必須分屬不同集合。因此我的處理方式是,每種取符號情況下,分別維護兩個武器集合的最值,求差值。(也有更巧妙的處理方法,如處理兩種武器的s值,最後再修正答案,這裏不贅述,可以看一下該題相關博客題解)

代碼:

#include<bits/stdc++.h>
#define dd(x) cout<<#x<<" = "<<x<<" "
#define de(x) cout<<#x<<" = "<<x<<"\n"
#define sz(x) int(x.size())
#define All(x) x.begin(),x.end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
typedef priority_queue<int> BQ;
typedef priority_queue<int,vector<int>,greater<int> > SQ;
const int maxn=1e5+10,mod=1e9+7,INF=0x3f3f3f3f;
int a[maxn][10],b[maxn][10];
void cal(int p[][10],int n,int k,int sta,ll& mx,ll& mn)
{
    mx=-1e18,mn=1e18;
    for (int i=0;i<n;++i)
    {
        ll tmp=0;
        for (int j=0;j<k;++j)
        {
            if (sta&(1<<j))
                tmp+=p[i][j];
            else
                tmp-=p[i][j];
        }
        mx=max(mx,tmp),mn=min(mn,tmp);
    }
}
ll max_Manhattan(int n,int m,int k)
{
    ll ans=0,amax,amin,bmax,bmin;
    for (int sta=0;sta<(1<<k);++sta)
    {
        cal(a,n,k,sta,amax,amin);
        cal(b,m,k,sta,bmax,bmin);
        ans=max(ans,max(amax-bmin,bmax-amin));
    }
    return ans;
}
int main()
{
    int  T;
    cin>>T;
    while (T--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for (int i=0;i<n;++i)
            for (int j=0;j<=k;++j)
                scanf("%d",&a[i][j]);
        for (int i=0;i<m;++i)
        {
            for (int j=0;j<=k;++j)
                scanf("%d",&b[i][j]);
            b[i][0]*=-1;
        }
        printf("%lld\n",max_Manhattan(n,m,k+1));
    }
    return 0;
}

最遠 Manhattan 距離