用java实现了(d)那个算法,贴出来大家给点意见哈:
4-7 Monge矩阵
一个m x n的实数矩阵A,如果对所有i,j,k和l,1≤ i<k ≤ m和1≤ j<l ≤ n,有
A[i,j]+A[k,l] ≤ A[i,l]+A[k,j]
那么,此矩阵A为Monge矩阵。换句话说,每当我们从Monge矩阵中挑出两行与两列,并且考虑行列交叉处的4个元素,左上角与右下角的和小于或等于左下角与右上角元素的和。
a)证明一个矩阵为Monge阵,当且仅当对所有i=1,2,...,m-1和j=1,2,...,n-1,有
A[i,j]+A[i+1,j+1] ≤ A[i,j+1]+A[i+1,j]
(提示:在当部分,对行、列分别使用归纳法。)
b)下面的矩阵不是Monge阵。改变一个元素,把它变成Monge阵(提示:利用a)的结论)
37 23 22 32
21 6 27 10
53 34 30 31
32 13 9 6
43 21 15 8
c) 假设f(i)是第i行包含最左端最小值的列的索引值。证明对任何的m x n Monge矩阵,有f(1) ≤ f(2) ≤...≤ f(m)。
d) 以下是一段关于分治算法的描述,用来计算m x n Monge矩阵A中每一行的最左端最小值:
构造一个包含所有A的偶数行的子矩阵A'。递归地计算A'中每一行的最左端最小值。然后计算A中奇数行的最左端最小值。
解释如何能在O(m+n)时间内计算出A的奇数行的最左端最小值?(假设偶数行最左端最小值已知)
e)写出d)部分所描述算法的运行时间的递归式,并证明其解为O(m+nlogm)
package com.yjh.monge; public class MongeMatrix { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[][] num = new int[][]{{10, 17, 13, 28, 23}, {17, 22, 16, 29, 23}, {24, 28, 22, 34, 24}, {11, 13, 6, 17, 7}, {45, 44, 32, 37, 23}, {36, 33, 19, 21, 6}, {75, 66, 51, 53, 34}}; Monge mm = new Monge(num); MongeItem[] min = mm.mongeSearchMin(num, 7); System.out.println("该Monge矩阵最左端最小值序列是:"); for(MongeItem i : min) System.out.print(i + ", "); } } //MongeItem类用来表示每行中最左端最小值元素及其列下标 class MongeItem { public int index; public int value; MongeItem(int value, int index) { this.index = index; this.value = value; } //定义toString() public String toString() { return this.value + ""; } } //Monge类用来表示Monge矩阵以及其相关操作 class Monge { private int x, y; //mongeArray的行和列 Monge(int[][] m) { x = m.length; y = m[0].length; } //mongeSearchMin()递归的找出最左端最小值序列 public MongeItem[] mongeSearchMin(int[][] monge1, int m) { MongeItem[] min = new MongeItem[m]; //min数组用来存储每一层的最左端最小值序列 //递归中最低层情况 if(m == 1) { int key1 = monge1[0][0]; min[0] = new MongeItem(key1 = monge1[0][0], 0); for(int i = 0; i < y; i++) { if(monge1[0][i] < key1) { min[0] = new MongeItem(key1 = monge1[0][i], i); } } return min; } else { //even[]用来得到该层Monge矩阵的偶数行组成的矩阵A' MongeItem even[] = mongeSearchMin(productArray(monge1, m, y), (int)(Math.ceil((double)m/2))); int jj = 0; //jj用来定位even[] //下面的循环利用A'找出奇数行中的最左端最小值序列放入min[]中 for(int i = 1; i < monge1.length; i = i + 2, jj++) { int key = monge1[i][even[jj].index]; min[i - 1] = even[jj]; min[i] = new MongeItem(key = monge1[i][even[jj].index], even[jj].index); //这里的try{}catch{}用来排除一个总行数m为偶数时的ArrayIndexOutOfBoundsException异常 try { //这里之所以(jj + 1 >= even.length && j < y)是因为当总行数m为偶数是不能借助even[jj + 1].index,只能循环到最后一列 for(int j = even[jj].index + 1; (jj + 1 >= even.length && j < y) || j <= even[jj + 1].index; j++) { if(monge1[i][j] < key) min[i] = new MongeItem(key = monge1[i][j], j); } } catch(Exception e) { e.getStackTrace(); } if(jj < even.length && i + 1 < monge1.length) min[i + 1] = even[jj + 1]; } return min; } } //用来从矩阵中取出偶数行 public int[][] productArray(int[][] oldArray, int m, int n) { int[][] newArray = new int[(int)(Math.ceil((double)m/2))][n]; int j = 0; for(int i = 0; i < oldArray.length; i=i+2) { try { newArray[j] = oldArray[i]; } catch(Exception e) { System.out.println(); } j++; } return newArray; } }