最遠 Manhattan 距離
阿新 • • 發佈:2018-12-27
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 距離