HDU 4666 经典的求最远曼哈顿距离

本文探讨了二维空间中计算最远曼哈顿距离的方法,通过分析坐标点的符号变化规律,得出结论:对于每个点,四种坐标组合的最大值存入数组,并利用STL的multiset进行组合求解,找到最大距离。

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

求最远曼哈顿距离,对于一个n维的空间,其中两点的曼哈顿距离为:|x1-y1|+|x2-y2|+|x3-y3|+|x4-y4|+……+|xn-yn|      (两点的坐标分别为(x1,x2,……,xn)、(y1,y2,……,yn))

以下以二维平面为例研究:        

设距离最远的两点为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) 再变一下,把中间变成‘+',

即 (xi+yi)+(-xj-yj), (-xi+yi)+(xj-yj), (xi-yi)+(-xj+yj),(-xi-yi)+(xj+yj)

由此,可以发现一个规律,即去绝对值之后把同一点的坐标放在一起,对应坐标的符号总是相反的,如(-xi+yi)与(xj-yj)。

假如我们用0表示负号,1表示正号,则(-xi+yi)与(xj-yj)两个括号内的符号可以表示为:01和10       

当你多举几个例子之后,就会发现,对于一个确定的维数D,符号转化成的二进制数,它们的和总是一个定值,即2^d-1,        这就说明了,当我们知道了前一个点去绝对值之后的符号,就可以知道第二个点去绝对值后的符号是怎样的

于是只要对所有的点(xi,yi),依次计算出(xi+yi),(xi-yi),(-xi+yi),(-xi-yi)这四种形式,然后把每个点i算出来的这四种情况的最大值分别记录到一个数组max[]中,然后枚举每一种去绝对值的组合,组合后的最大值即为answer


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;
#define  N 200
int  a[N], num[N*301][N];
int  main()
{
     int n, m, op, x;
     while(~scanf("%d %d", &n, &m))
     {
          multiset<int>  s[N];
          for(int i = 1; i <= n; i ++)
          {
                  scanf("%d", &op);
                  int temp = 1<<m;
                  if(op == 0)
                  {
                        for(int j = 1; j <= m; j ++)
                        {
                                scanf("%d", &a[j]);
                        }
                        for(int j = 0; j < temp; j ++)
                        {
                                int t = j, sum=0;
                                for(int k = 1; k <= m; k ++)
                                {
                                        if((1<<(k-1))&j)   sum += a[k];
                                        else  sum -= a[k];
                                      // t = t << 1;
                                }
                                num[i][j] = sum;
                                s[j].insert(sum);
                        }
                  }
                  else
                  {
                        scanf("%d", &x);
                        for(int j = 0; j < temp; j ++)
                              s[j].erase(s[j].find(num[x][j]));
                  }
                  int ans = 0;
                  for(int i = 0; i < temp; i ++)
                  {
                          multiset<int>::iterator it1 = s[i].begin();
                          multiset<int>::iterator it2 = s[i].end();
                          it2--;
                          ans = max(*it2 - *it1, ans);
                  }
                  printf("%d\n", ans);
          }
     }


}

此题用multiset实现。其实multiset和set的区别就是multiset允许重复值的存在,其他很多操作基本上都是相同的。

STL的multiset示例代码:


#include <iostream>
#include <set>
#include <iterator>
using namespace std;

int main()
{
	typedef multiset<int, greater<int> > IntSet;

	IntSet coll1;

	coll1.insert(4);
	coll1.insert(3);
	coll1.insert(5);
	coll1.insert(1);
	coll1.insert(6);
	coll1.insert(2);
	coll1.insert(5);

	IntSet::iterator pos;
	for(pos = coll1.begin(); pos != coll1.end(); ++pos)
	{
		cout << *pos << ' ';
	}
	cout << endl;

	IntSet::iterator ipos = coll1.insert(4);
	cout << "4 inserted as element "
		 << distance(coll1.begin(), ipos) + 1
		 << endl;

	multiset<int> coll2(coll1.begin(), coll1.end());
	copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	coll2.erase(coll2.begin(), coll2.find(3));

	int num;
	num = coll2.erase(5);
	cout << num << " elements removed" << endl;

	copy(coll2.begin(), coll2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值