当前编程题:动态规划算法解矩阵连乘(动态规划)—动态规划算法解矩阵连乘(动态规划)
【问题描述】使用动态规划算法解矩阵连乘问题,具体来说就是,依据其递归式自底向上的方式进行计算,在计算过程中,保存已子问题答案,每个子问题只解决一次,在后面计算需要时只要简单查一下得到其结果,从而避免大量的重复计算,最终得到多项式时间的算法。
【输入形式】在屏幕上输入矩阵连乘个数,和第1个矩阵的行数和第1个矩阵到第n个矩阵的列数,各数间都以一个空格分隔。
【输出形式】矩阵m,其中m(i,j)中存放的是:计算Ai:j所需的最少数乘次数。矩阵s,其中s[i][j]记录了断开的位置,即最优的加括号方式应为(A[i:s[i][j]])*(A[s[i][j]+1:j])。矩阵连乘A1…An的最优计算次序。
【样例输入】
6
30 35 15 5 10 20 25
【样例输出】
[[ 0 15750 7875 9375 11875 15125]
[ 0 0 2625 4375 7125 10500]
[ 0 0 0 750 2500 5375]
[ 0 0 0 0 1000 3500]
[ 0 0 0 0 0 5000]
[ 0 0 0 0 0 0]]
[[0 1 1 3 3 3]
[0 0 2 3 3 3]
[0 0 0 3 3 3]
[0 0 0 0 4 5]
[0 0 0 0 0 5]
[0 0 0 0 0 0]]
((A1(A2A3))((A4A5)A6))
【样例说明】
输入:矩阵连乘个数为6,第1个矩阵的行数和第1个矩阵到第n个矩阵的列数,以空格分隔。
输出:矩阵m,s,和矩阵连乘的最优计算次序。
【评分标准】根据输入得到准确的输出。
python:
import numpy as np
def matrix_chain(p, n, s, m):
for Len in range(2, n+1):
for i in range(1, n-Len+2):
j = i+Len-1
m[i, j] = m[i+1, j] + p[i-1]*p[i]*p[j]
s[i, j] = i
for k in range(i+1, j): # i+1
q = m[i, k] + m[k+1, j] + p[i-1]*p[k]*p[j]
if q < m[i, j]:
m[i, j] = q
s[i, j] = k
def print_optimal_parens(s, i, j):
if i == j:
print("A"+str(i), end='') # end=''
else:
print("(", end='')
print_optimal_parens(s, i, s[i, j])
print_optimal_parens(s, s[i, j]+1, j)
print(")", end='')
def main():
n = int(input())
p = np.array(list(map(int, input().split())))
m = np.zeros([n+1, n+1], dtype=int)
s = np.zeros([n+1, n+1], dtype=int)
matrix_chain(p, n, s, m)
print(m[1:n+1, 1:n+1])
print(s[1:n+1, 1:n+1])
print_optimal_parens(s, 1, n)
if __name__ == '__main__':
main()
C++:
#include<iostream>
using namespace std;
const int MAX=1000;
int p[MAX+1]; //记录相邻矩阵的行列值
int m[MAX][MAX]; //记录数乘次数最优解 最终解值为m[1][n];
int s[MAX][MAX]; //记录划分括号位置
int n;
void Matrix_chain(){
for(int i=1;i<=n;i++)
m[i][i]=0;
for(int r=2;r<=n;r++)
for(int i=1;i<=n-r+1;i++){
int j=r+i-1;
m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(int k=i+1; k<j; k++){
int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(temp<m[i][j]){
m[i][j]=temp;
s[i][j]=k;
}
}
}
}
void Print_optimal_parens(int i,int j){
if(i==j)
cout<<"A"<<i;
else{
cout<<"(";
Print_optimal_parens(i,s[i][j]);
Print_optimal_parens(s[i][j]+1,j);
cout<<")";
}
}
int main(){
cin>>n;
for(int i=0;i<=n;i++)
cin>>p[i];
Matrix_chain();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<m[i][j]<<" ";
cout<<endl;
}
cout<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<s[i][j]<<" ";
cout<<endl;
}
Print_optimal_parens(1,n);
return 0;
}
老师的参考代码:
import numpy as np
def dynamic_matrix_chain(p, n):
m = np.zeros((n+1, n+1), dtype=np.double)
s = np.zeros((n+1, n+1), dtype=np.int8)
for len in range(2, n+1):
for i in range(1, n-len+2):
j = i+len-1
m[i, j] = np.inf
for k in range(i, j):
q = m[i, k]+m[k+1, j]+p[i-1]*p[i]*p[j]
if q < m[i, j]:
m[i, j] = q
s[i, j] = k
return m, s
def print_optimal_parens(s, i, j):
if i == j:
print("A%d" % i, end="")
else:
print("(", end="")
print_optimal_parens(s, i, s[i, j])
print_optimal_parens(s, s[i, j]+1, j)
print(")", end="")
def main():
n = int(input())
p = input().split()
p = np.array(p, dtype=np.double)
m, s = dynamic_matrix_chain(p, n)
m = m.astype(int)
print(m[1:, 1:])
print(s[1:, 1:])
print_optimal_parens(s, 1, n)
if __name__ == '__main__':
main()