HDU4666 Hyperspace multiset&Manhattan距离

本文详细解析了HDU4666题目的解题思路,介绍了曼哈顿距离的概念及其计算方法,并通过具体示例说明如何在多维空间中求解最大曼哈顿距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值