【试题四】(共15分)
阅读下列说明和C代码,回答问题1至问题3,将解答写在答题纸的对应栏内。
工程计算中经常要完成多个矩阵相乘的计算任务,对矩阵相乘进行以下说明。
(1)两个矩阵相乘要求第一个矩阵的列数等于第二个矩阵的行数,计算量主要由进行乘法运算的次数决定,假设采用标准的矩阵相乘算法,计算Amxn*Bnxp需要m*n*p次乘法运算,即时间复杂度为O(m*n*p)。
(2)矩阵相乘满足结合律,多个矩阵相乘时不同的计算顺序会产生不同的计算量。以矩阵三个矩阵相乘为例,若按(A1*A2)*A3计算,则需要进行5*100*8+5*8*50=6000次乘法运算,若按A1*(A2*A3)计算,则需要进行100*8*50+ 5*100*50=65000次乘法运算。
矩阵链乘问题可描述为:给定n个矩阵,矩阵Ai的维数为Pi-1×Pi其中i=1, 2,..., n。确定一种乘法顺序,使得这n个矩阵相乘时进行乘法的运算次数最少。由于可能的计算顺序数量非常庞大,对较大的n,用蛮力法确定计算顺序是不实际的。经过对问题进行分析,发现矩阵链乘问题具有最优子结构,即若A1*A2**An的一个最优计算顺序从第k个矩阵处断开,即分为A1*A2*…*Ak和Ak+1*Ak+2**An两个子问题,则该最优解应该包含A1*A2**Ak的一个最优计算顺序和Ak+1*Ak+2**An的一个最优计算顺序。据此构造递归式:
其中,cost[i][j]表示Ai+1*Ai+2*Aj+1的最优计算的计算代价。最终需要求解cost[0][n-1]。
C代码算法实现,采用自底向上的计算过程。首先计算两个矩阵相乘的计算量,然后依次计算3个矩阵、4个矩阵、…、n个矩阵相乘的最小计算量及最优计算顺序。下面是该算法的语言实现:
(1)主要变量说明
n:矩阵数
seq:矩阵维数序列
cost[][]:二维数组,长度为n*n,其中元素cost[i][j]表示Ai+1*Ai+2*...*Aj+1的最优的计算代价
trace[][]:二维数组,长度为n*n,其中元素costcost
#include<stdio.h>
#include<stdlib.h>
#define N 100
int cost[N][N];//元素cost[i][j]表示Ai+1*Ai+2*...*Aj+1的最优的计算代价
int trace[N][N];//trace[i][j]表示Ai+1*Ai+2*...*Aj+1的最优计算对应的划分位置,即k(2)函数cmm
int cmm1(int n, int seq[]) {
//seq:矩阵维数序列
int tempCost;
int tempTrace;
int i, j, k, p;
int temp;
for (i=0; i < n; i++) {
cost[i][i] =0;
}
for (p= 1; p < n; p++) {
for (i= 0; i<n-p ; i++) {//填空1
j=i+p; //填空2
tempCost=-1;
for (k= i; k<j ; k++) {
temp = cost[i][k]+cost[k+1][j]+seq[i]*seq[k+1]*seq[j+1];//填空3
if (tempCost == -1 || tempCost > temp) {
tempCost = temp;
tempTrace=k;//填空4
}
cost[i][j] = tempCost;
trace[i][j]=tempTrace;
}
}
}
return cost[0][n - 1];
}
int main(){
//A1为15*5,A2为5*10,A3为10*20,A4为20*25
int seq[]={15,5,10,20,25};
int cmm=cmm1(4,seq);
printf("%d\n",cmm);
return 0;
}
问题1(8分)
根据以上说明和C代码,填写C代码中的空(1)~(4)。
问题2(4分)
根据以上说明和C代码,该问题采用了( 5 )算法设计策略,时间复杂度为( 6 )(用O符号表示)。
问题3(3分)
考虑实例n=4,各个矩阵的维数为A1为15*5,A2为5*10,A3为10*20,A4为20*25,即维度序列为15,5,10,20和25。则根据上述C代码得到的一个最优计算顺序为( 7 )(用加括号方式表示计算顺序),所需要的乘法运算次数为( 8 )。
试题六(共15分)
阅读下列说明和Java代码,将应填入(n)处的字句写在答题纸的对应栏内。
在软件系统中,通常会给用户提供取消、不确定或者错误操作的选择,允许将系统恢复到原先的状态。现使用备忘录(Memento)模式实现该要求,得到如图5-1所示的类图。Memento 包含了要被恢复的状态。Originator创建并在Memento中存储状态。Caretaker负责从Memento中恢复状态。
【JAVA代码】
package test_2022_1;
import java.util.*;
class Memento {
private String state;
public Memento (String state) {this.state=state;}
public String getState() {return state; }
}
class Originator{
private String state;
public void setState (String state) {this.state=state; }
public String getState() { return state; }
public Memento saveStateToMemento() {
return new Memento(state);//填空1
}
public void getStateFromMemento(Memento Memento){
state = Memento.getState() ;//填空2
}
}
class CareTaker {
public void add(Memento state){
mementoList.add(state);
}
public Memento get(int index){
return mementoList.get(index);
}
}
class MementoPatternDemo{
public static void main (String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("State #1");
originator.setState("State #2");
careTaker.add(originator.saveStateToMemento());//填空5
originator.setState("State #3");
careTaker.add(originator.saveStateToMemento());//填空5
originator.setState("State #4");
}
}
public class MementoDemo{
}