bitmap求哈密顿距离-给定N(1<=N<=100000)个五维的点A(x1,x2,x3,x4,x5),求两个点X(x1,x2,x3,x4,x5)和Y(

本文介绍了一种求解高维空间中两点间哈密顿距离最大值的问题,并提供了两种解决方案:暴力遍历和利用位图(bitmap)进行优化计算。通过对问题的详细解析,文章深入探讨了位图在优化计算过程中的应用。

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

Java代码 复制代码 收藏代码
  1. import java.util.Random;
  2. /**
  3. * 题目:
  4. * 给定N(1<=N<=100000)个五维的点A(x1,x2,x3,x4,x5),求两个点X(x1,x2,x3,x4,x5)和Y(y1,y2,y3,y4,y5),
  5. * 使得他们的哈密顿距离(d=|x1-y1| + |x2-y2| + |x3-y3| + |x4-y4| + |x5-y5|)最大。|x|=abs(x)。
  6. *
  7. * 第一种方法当然是暴力遍历一次,求得最大值
  8. * 第二种方法借助bitmap
  9. * 在网上找了两个相关的资料:
  10. * http://www.cppblog.com/sonicmisora/archive/2009/09/14/96143.aspx
  11. * http://wenku.baidu.com/view/1e51750abb68a98271fefaa8.html
  12. *
  13. * 我觉得这两个资料都不好理解
  14. * 我的理解如下:
  15. * 1.
  16. * 这道题目里面,使用bitmap的关键是这个:
  17. * 先看二维的点,我们约定形如Xij下标的数字(ij)是二进制,0表示正数,1表示负数,令
  18. * X00= x1 + x2
  19. * X01= x1 - x2
  20. * X10= - x1 + x2
  21. * X11= - x1 - x2
  22. * 用一个一维数组a保存这四个值,即a[0]=X00,a[1]=X01,a[2]=X10,a[3]=X11
  23. * 有N个点,那么就有二维数组:A[N][S],(S=00,01,10,11)
  24. *
  25. * 2.(当然,更严谨的数学证明请参考上面提到的第二个链接)
  26. * |x1-y1| = MAX(x1-y1, y1-x1);
  27. * => |x1-y1| + |x2-y2| =
  28. MAX{
  29. (x1-y1)+(x2-y2)
  30. (x1-y1)-(x2-y2)
  31. -(x1-y1)+(x2-y2)
  32. -(x1-y1)-(x2-y2)
  33. };
  34. 也就是=
  35. MAX{
  36. (x1+x2)-(y1+y2)
  37. (x1-x2)-(y1-y2)
  38. (-x1+x2)-(-y1+y2)
  39. (-x1-x2)-(-y1-y2)
  40. };
  41. 正好是MAX{(X00-Y00), (X01-Y01), (X10-Y10), (X11-Y11)};
  42. 如果有A-Z共26个点,那么
  43. result = MAX{
  44. (A00-B00), (A01-B01), (A10-B10), (A11-B11),
  45. (A00-C00), (A01-C01), (A10-C10), (A11-C11),
  46. ......
  47. (X00-Y00), (X01-Y01), (X10-Y10), (X11-Y11),
  48. (Y00-Z00), (Y01-Z01), (Y10-Z10), (Y11-Z11),
  49. };
  50. 对上面的每一列应用MAX运算:
  51. 对ij=00,时,第一列有MAX(第一列)=MAX(A00,B00...Z00) - Min(A00,B00...Z00)
  52. 那么 result = MAX{MAX(第一列),MAX(第二列)...};
  53. 也就是上面提到的第一个链接里面的说法,引用一下:
  54. A[1][0]-A[2][0]
  55. A[1][1]-A[2][1]
  56. A[1][2]-A[2][2]
  57. A[1][3]-A[2][3]
  58. 然后问题就变得简单了,扫一遍,对于每个I,求出A[*][I]的最大值MAX(I)最小值MIN(I),
  59. 再用MAX(I)-MIN(I)就可以得到对于I来说的最大值了。最后取个总的最大值
  60. * @author bylijinnan
  61. */
  62. public class HamiltonDistance {
  63. private final int N = 10 * 1000;
  64. private final int D = 5;
  65. private final int S = 1 << D;
  66. public static void main(String[] args) {
  67. HamiltonDistance h = new HamiltonDistance();
  68. h.test();
  69. }
  70. public void test() {
  71. int[][] data = sourceData();
  72. System.out.println(maxHamiltonDistance(data));
  73. System.out.println(maxHamiltonDistanceBitMap(data));
  74. }
  75. /**
  76. * 通过枚举暴力求解
  77. * @param data
  78. * @return
  79. */
  80. public long maxHamiltonDistance(int[][] data) {
  81. if (data == null || data.length != N || data[0].length != D) {
  82. System.out.println("invalid input");
  83. return 0L;
  84. }
  85. long result = 0L;
  86. for(int i = 0; i < N; i++) {
  87. int[] pointA = data[i];
  88. for(int j = i + 1; j < N; j++) {
  89. int[] pointB = data[j];
  90. long distance = distanceOfTwoPoints(pointA, pointB);
  91. if (result < distance) {
  92. result = distance;
  93. }
  94. }
  95. }
  96. return result;
  97. }
  98. //求得:|X1-Y1| + |X2-Y2| + |X3-Y3| + |X4-Y4| + |X5-Y5| + ...|Xn-Yn|
  99. private long distanceOfTwoPoints(int[] pointA, int[] pointB) {
  100. long result = 0L;
  101. for(int i = 0; i < D; i++) {
  102. result += Math.abs((long)pointA[i] - (long)pointB[i]);
  103. }
  104. return result;
  105. }
  106. /**
  107. * 通过bitmap求解
  108. * @param data
  109. * @return
  110. */
  111. public long maxHamiltonDistanceBitMap(int[][] data) {
  112. //略去输入合法性检查
  113. long result = Long.MIN_VALUE;
  114. //求得X00000~X11111,下标是二进制
  115. long[][] A = new long[N][S];
  116. for (int i = 0; i < N; i++) {
  117. for (int j = 0; j < S; j++) {
  118. A[i][j] = getSumByBits(data[i], j);
  119. }
  120. }
  121. //System.out.println(Arrays.deepToString(A));
  122. long MAXi = Long.MIN_VALUE;
  123. long MINi = Long.MAX_VALUE;
  124. for (int i = 0; i < S; i++) {
  125. for (int j = 0; j < N; j++) {
  126. if (MAXi < A[j][i]) {
  127. MAXi = A[j][i];
  128. }
  129. if (MINi > A[j][i]) {
  130. MINi = A[j][i];
  131. }
  132. }
  133. result = max(result, (MAXi - MINi));
  134. MAXi = Long.MIN_VALUE;
  135. MINi = Long.MAX_VALUE;
  136. }
  137. return result;
  138. }
  139. //0表示正数,1表示负数
  140. private long getSumByBits(int[] a, int s) {
  141. long result = 0L;
  142. for (int i = 0; i < D; i++) {
  143. if (exist(s, i)) {
  144. result -= a[i];
  145. } else {
  146. result += a[i];
  147. }
  148. }
  149. return result;
  150. }   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值