题目如下:

 

 

已知平面上若干个点的坐标。

需要求出在所有的组合中,4个点间平均距离的最小值(四舍五入,保留2位小数)。

比如有4个点:a,b,c,d,则平均距离是指:ab, ac, ad, bc, bd, cd 这6个距离的平均值。

每个点的坐标表示为:横坐标,纵坐标

坐标的取值范围是:1~1000

所有点的坐标记录在in.txt中,请读入该文件,然后计算。

注意:我们测试您的程序的时候,in.txt 可能会很大,比如包含上万条记录。

举例:

如果,in.txt 内的值为:


10,10

20,20

80,50

10,20

20,10


则程序应该输出:

11.38

 

解题的关键是:上面红色的文字,上万条记录。

点的数量小的话,直接用10试探法,很容易就可以得出答案。

评分标准里说:考查考生对算法的优化。

 

如果直接用10试探,当点数量到达1000的时候,经测试要一分钟+,就这个题目。

所以说,上w个点更加不行了,所以这个算法已经否定。

其实一开始自己也没有想到更为绝妙的算法。后来经老师指点了一下:把平面上的点分块。就这么一句话,我们把思路想出来了,然后不到10分钟,代码也出来了。1w个点也不是问题。我测试过6000个点,一般10秒左右就可以算出。所以,找方法是最最重要的。

在此我做一张图,以更让读者简单易懂

11年蓝桥杯决赛第5题,分析和解答_第1张图片

如图,区域分为4*4的小方块,蓝色方块每个方块内的点做组合,计算平均距离,绿色方块同理,这样可以遍历所有的方块,直到找出平均距离最短的4点。这样,算法非常容易就能写出来。可以想到:假如一个方块内只有3个点或者小于3个点,那么这三个点就完全不用考虑了,自己可以想到。这样另外一个问题出来了,也是这个方法最致命的一点:假如每一个划分的小方块都最多只能找到3个点呢?问题就在这里,解决也不是没有办法,这就是区块划分的问题了,动态规划它,但是这个没有定量,所以也很难确定最优时间区块的划分,因为所有点不清楚分布的分散与否。

以下为我的代码,java代码:

 

 
    
  1. import java.io.IOException; 
  2. import java.io.RandomAccessFile; 
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5.  
  6.  
  7. public class Ti5Demo { 
  8.  
  9.     static boolean first = false ; // 是否是第一次记录最小距离 
  10.     static boolean has10 = false ; // 是否找到10 
  11.     static float minL = 0 ; // 记录当前计算出来的最小距离 
  12.     static float tempL = 0 ; // 临时记录当前的最小距离 
  13.     static int[] tempDot = new int[4] ; // 这个是临时保存这4个点在List中的位置 
  14.     static float a1, a2, a3, a4, a5, a6 ; // 临时存放4点的6个距离 
  15.      
  16.     public static void main(String[] args) throws IOException { 
  17.         List arr = new ArrayList() ; 
  18.         List tArr = new ArrayList() ; 
  19.          
  20.         String curr ; 
  21.         RandomAccessFile r = new RandomAccessFile("src/p4.txt""r") ; 
  22.         while(r.read() != -1) { 
  23.             r.seek(r.getFilePointer()-1) ; 
  24.             curr = r.readLine() ; 
  25.             Node n = new Node() ; 
  26.             String te[] = curr.split(",") ; 
  27.             n.x = Integer.valueOf(te[0]) ; 
  28.             n.y = Integer.valueOf(te[1]) ; 
  29.             arr.add(n) ; 
  30.         } 
  31.          
  32.         /** 
  33.          * 历遍每一个小方块,逐个计算 
  34.          */ 
  35.         int i, j, k, l ; // i,j为x轴最小值和最大值,k,l为y轴最小值和最大值 
  36.         int t ; // 查找的临时变量 
  37.         int dia = 5 ; // 分块的大小 
  38.         long time = System.currentTimeMillis() ; 
  39.         for(i = 0, j = dia*2; j <= 1000; i+=dia, j+=dia) { 
  40.             for(k = 0, l = dia*2; l <= 1000; k+=dia, l+=dia) { 
  41.                 for(t = 0; t < arr.size(); t++) { 
  42.                     if(arr.get(t).x >= i && arr.get(t).x <= j && arr.get(t).y >= k && arr.get(t).y <= l) { 
  43.                         tArr.add(arr.get(t)) ; 
  44.                     } 
  45.                 } 
  46.                 if(tArr.size() > 3) { 
  47.                     p(tArr) ; 
  48.                 } 
  49.                 tArr.clear() ; 
  50.             } 
  51.         } 
  52.         System.out.println("用时:" + (System.currentTimeMillis() - time)) ; 
  53.         System.out.printf("%3.2f", minL) ; 
  54.          
  55.     } 
  56.      
  57.     /** 
  58.      * 求4个点的平均距离,并比较当前已记录的最小距离,并更新最小距离变量 
  59.      * @param arr 
  60.      * @param numArr 
  61.      * @return 
  62.      */ 
  63.     public static void co(List arr, int[] numArr) { 
  64.         int temp = 0 ; 
  65.         for(int i = 0; i < numArr.length; i++) { 
  66.             if(numArr[i] == 1) { 
  67.                 tempDot[temp] = i ; 
  68.                 temp++ ; 
  69.             } 
  70.         } 
  71.          
  72.         a1 = twoDot(arr.get(tempDot[0]), arr.get(tempDot[1])) ; 
  73.         a2 = twoDot(arr.get(tempDot[0]), arr.get(tempDot[2])) ; 
  74.         a3 = twoDot(arr.get(tempDot[0]), arr.get(tempDot[3])) ; 
  75.         a4 = twoDot(arr.get(tempDot[1]), arr.get(tempDot[2])) ; 
  76.         a5 = twoDot(arr.get(tempDot[1]), arr.get(tempDot[3])) ; 
  77.         a6 = twoDot(arr.get(tempDot[2]), arr.get(tempDot[3])) ; 
  78.          
  79.         tempL = (a1 + a2 + a3 + a4 + a5 + a6) / 6 ; 
  80.         if(first == true) { 
  81.             if(minL > tempL) { 
  82.                 minL = tempL ; 
  83.             } 
  84.         }else if(first == false) { 
  85.             minL = tempL ; 
  86.             first = true ; 
  87.         } 
  88.     } 
  89.      
  90.     /** 
  91.      * 计算两点间距离 
  92.      * @param n1 
  93.      * @param n2 
  94.      * @return 
  95.      */ 
  96.     public static float twoDot(Node n1, Node n2) { 
  97.         float x = Math.abs(n1.x - n2.x) ; 
  98.         float y = Math.abs(n1.y - n2.y) ; 
  99.         return (float) Math.sqrt(x*x + y*y) ; 
  100.     } 
  101.      
  102.     /** 
  103.      * 组合处理代码 
  104.      * @param arr 
  105.      */ 
  106.     public static void p(List arr) { 
  107.         int[] num = new int[arr.size()] ; 
  108.         for(int i = 0; i < 4; i++) { 
  109.             num[i] = 1 ; 
  110.         } 
  111.         has10 = false ; 
  112.         co(arr, num) ; // 计算4个点 
  113.         while(true) { 
  114.             int left1 = 0 ; 
  115.             int bound; //第一个"10"组合的索引 
  116.             for(int i = 0; i < arr.size()-1; i++) { 
  117.                 if(num[i] == 1 && num[i+1] == 0) { 
  118.                     bound = i ; 
  119.                     num[i] = 0 ; 
  120.                     num[i+1] = 1 ; 
  121.                     for(int j = 0; j < left1; j++) { 
  122.                         num[j] = 1 ; 
  123.                     } 
  124.                     for(int j = left1; j < bound; j++) { 
  125.                         num[j] = 0 ; 
  126.                     } 
  127.                     has10 = true ; 
  128.                     break ; 
  129.                 }else if(num[i] == 1) { 
  130.                     left1++ ; // =2 
  131.                 } 
  132.             } 
  133.             if(has10 == false) { 
  134.                 break ; 
  135.             } 
  136.             co(arr, num) ; // 计算4个点 
  137.             has10 = false ; 
  138.         } 
  139.     } 
  140.