题目链接:HDU4666
题目大意:给你 q个事件,在k维空间,每个事件会出现一个点或者消失一个点,出现一个点会给出该点在k维空间下的坐标,消失一个点会给出消失的点是在哪个事件中出现的,求每次事件中最大的Manhattan距离(曼哈顿距离)。
代码参考:大佬的代码 我在原代码的基础上加上了一些注释,便于大家理解
知识点:
1、曼哈顿距离?
闵可夫斯基距离(Minkowsk distance)-MinkowskiDistanceMeasure(默认p=3)
可看成是欧氏距离的指数推广,还没有见到过很好的应用实例,但通常,推广都是一种进步,特别的,
当p=1,也成做曼哈顿距离,也称绝对距离,曼哈顿距离来源于城市区块距离,是将多个维度上的距离进行求和后的结果。ManhattanDistanceMeasure.
2、
以二维平面为例:
设距离最远的两点为 i, j,可知所求的最大距离必定有以下四种形式之一:
(xi-xj)+(yi-yj), (xj-xi)+(yi-yj), (xi-xj)+(yj-yi), (xj-xi)+(yj-yi) ,这个部分应该都没问题吧,
然后变形一下,把相同点的坐标放到一起,即 (xi+yi)-(xj+yj), (-xi+yi)-(-xj+yj), (xi-yi)-(xj-yj), (-xi-yi)-(-xj-yj),
可以发现即去绝对值之后把同一点的坐标放在一起,对应坐标符号相同。这句话多理解几遍!
举个例子就很清楚了, 比如 (10,-2) (-2,10) 其Manhattan距离为24,那我们来看看这个是怎么算出来的。
10 - (-2)+|-2-10|=24 实质为 10-(-2)+2-(-10)
在这道题中,我们把每个坐标的所有正负情况枚举,也就是2^k种情况,
比如二维平面,x1=10 y1=-2 那么有2^2=4种形式 (x1,y1) (-x1,y1) (x1,-y1 )(-x1,-y1) ,
正正10-2=8 负正-10-2=-12 正负10-(-2)=12 负负-10-(-2)=-8
对应的(-2,10)同样有4种情况,正正-2 +10=8 负正2+10=12 正负-2-10=-12 负负2-10=-8
又因为上面得出的结论,最大值对应坐标符号相同,所以我们可以用每种情况的最大值减去最小值即可得出最大值 12-(-12)=24.
说白了,就是让我们计算这两点之间的距离 (10,-2) (-2,10) 代码化,我们直观就可以看出 距离为 10-(-2)+10-(-2) 代码实现就是找到 正负这种情况,相减。
我说了这么多,就是为了解释这句话,对应坐标符号相同。如果这句话懂了,那么这题你也搞明白了。
3、另外在这道题中,学习了multiset的应用,首先集合中可以有重复的元素,元素会按照从小到大排序,可以用find()去找某个元素的值,insert()增加,erase()删除,遍历的时候用迭代器 iterator,end()指向最后一个元素后一位。取值用*it
AC代码:
/* HDU4666 2017年8月6日08:18:38 手敲一遍 multiset 的应用 AC */ #include<stdio.h> #include<set> #include<algorithm> using namespace std; const int maxn=60000+10; int n,m,num[maxn][10]; multiset<int> mst[1<<5]; multiset<int>::iterator it1,it2; int main(){ while(~scanf("%d%d",&n,&m)){ /*每次循环将多重集清空*/ for(int i=0;i<(1<<5);i++){ mst[i].clear(); } int od,x; for(int i=1;i<=n;i++){ scanf("%d",&od); if(od==0){ for(int j=0;j<m;j++){ scanf("%d",&num[i][j]); } /*如果是m维度 那么每个坐标对应 2^m种组合 0-2^m-1 比如二维 a,b 对应4种组合 a b a -b -a b -a -b */ for(int j=0;j<(1<<m);j++){ int sum=0; for(int k=0;k<m;k++){ //这个比较难理解 if(j&(1<<k)) sum+=num[i][k]; else sum-=num[i][k]; } mst[j].insert(sum); } } else{ scanf("%d",&x); for(int j=0;j<(1<<m);j++){ int sum=0; for(int k=0;k<m;k++){ if(j&(1<<k)) sum+=num[x][k]; else sum-=num[x][k]; } it1=mst[j].find(sum); mst[j].erase(it1); } } int ans=0; for(int j=0;j<(1<<m);j++){ it1=mst[j].end(); it1--;//因为end指向最后一个数据的后一位,所以往后挪一位。 it2=mst[j].begin(); ans=max(ans,*it1-*it2); } printf("%d\n",ans); } } return 0; }
