用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;
}
}