HDU4666 Hyperspace(数学推理+数据结构)
问题领悟:
1)求两点的曼哈顿距离
2)求n个点中最大的曼哈顿距离(朴素算法:O(n^2) ) [在不考虑删除操作的情况下]
3)加入删除操作,如果前面已求得的最大距离若有一个被删去,则需要重新计算最大曼哈顿距离,最坏情况时间复杂度可达O(n^3) ;远远超出。
问题思考:
1)首先能不能找到问题的一种朴素算法,使复杂度为O(n^2)的,在10s时间下可以试试;
2)期待这类O(n^2)问题的更高效的算法!
A.思考方向1:可能要用数据结构优化到O(nlg(n));
3)不存在,那就考虑问题本身具有的特殊性,或挖掘出问题本身的性质和规律:
曼哈顿距离:|x1-x2| + |y1-y2|
求最大值。
怎么考察此式的性质?
将式拆分,重组,得:
我们可以发现一个规律点:即不同点相对应的维数必然符号相反,如同一个式中,xi必然对应着-yi,由此将后面式子负号提出,用01二进制每个点内部各维数间的正负号,得到对应两个相同符号的式子相减的表达式,如对于二维(xi,xj),(yi,yj) ,用二维数组 A[N][2^k] 保存N*(2^k)个数据可分解如下:
|xi-yi| + |xj-yj|=
max{
A[1][0]-A[2][0]
A[1][1]-A[2][1]
A[1][2]-A[2][2]
A[1][3]-A[2][3]
}
所以对于2^k中每一个数(即表示单个点内个位数间的运算符号),运算后保存在方便查找最值且下标为K的数据结构中(如堆,优先队列,multiset集合等),遍历2^k种情况,最大最小值,相减找出最大差值即可:
源程序:
#include <iostream> #include <cstdio> #include <cstring> #include <set> using namespace std; #define maxn 60005 #define Max(a,b) (a)>(b)?(a):(b) #define Min(a,b) (a)<(b)?(a):(b) multiset<int> mset[1<<5]; int arr[maxn][6]; int main() { int q,k,i,j,l,op,ith,sum,ma; while(~scanf("%d%d",&q,&k)) { for(i=0;i<(1<<k);i++) mset[i].clear(); //注意容器的初始化清空! for(i=1;i<=q;i++) { scanf("%d",&op); if(!op) { for(j=0;j<k;j++) scanf("%d",&arr[i][j]); for(j=0;j<(1<<k);j++) { sum=0; for(l=0;l<k;l++) { if(j&(1<<l)) sum+=arr[i][l]; else sum-=arr[i][l]; } mset[j].insert(sum); } } else { scanf("%d",&ith); for(j=0;j<(1<<k);j++) { sum=0; for(l=0;l<k;l++) { if(j&(1<<l)) sum+=arr[ith][l]; else sum-=arr[ith][l]; } multiset<int>::iterator it; it=mset[j].find(sum); mset[j].erase(it); } } ma=0; multiset<int>::iterator it1,it2; for(j=0;j<(1<<k);j++) { it1=mset[j].begin(); it2=mset[j].end(); it2--; ma=Max(ma,*it2-*it1); } printf("%d\n",ma); } } return 0; }