杭电 1082【矩阵乘法次数的运算】

来源:互联网 发布:ubuntu openssh国内源 编辑:程序博客网 时间:2024/04/29 19:06

Matrix Chain Multiplication

Problem Description
Matrix multiplication problem is a typical example of dynamical programming.
Suppose you have to evaluate an expression like A*B*C*D*E where A,B,C,D and E are matrices. Since matrix multiplication is associative, the order in which multiplications are performed is arbitrary. However, the number of elementary multiplications needed strongly depends on the evaluation order you choose.
For example, let A be a 50*10 matrix, B a 10*20 matrix and C a 20*5 matrix.
There are two different strategies to compute A*B*C, namely (A*B)*C and A*(B*C).
The first one takes 15000 elementary multiplications, but the second one only 3500.
Your job is to write a program that determines the number of elementary multiplications needed for a given evaluation strategy.
 
Input
Input consists of two parts: a list of matrices and a list of expressions.
The first line of the input file contains one integer n (1 <= n <= 26), representing the number of matrices in the first part. The next n lines each contain one capital letter, specifying the name of the matrix, and two integers, specifying the number of rows and columns of the matrix.
The second part of the input file strictly adheres to the following syntax (given in EBNF):
SecondPart = Line { Line } <EOF>
Line = Expression <CR>
Expression = Matrix | "(" Expression Expression ")"
Matrix = "A" | "B" | "C" | ... | "X" | "Y" | "Z"
 
Output
For each expression found in the second part of the input file, print one line containing the word "error" if evaluation of the expression leads to an error due to non-matching matrices. Otherwise print one line containing the number of elementary multiplications needed to evaluate the expression in the way specified by the parentheses.

Sample Input
9A 50 10B 10 20C 20 5D 30 35E 35 15F 15 5G 5 10H 10 20I 20 25ABC(AA)(AB)(AC)(A(BC))((AB)C)(((((DE)F)G)H)I)(D(E(F(G(HI)))))((D(EF))((GH)I))

Sample Output
000error10000error350015000405004750015125
 
/**矩阵乘法次数的运算**运算思想:利用栈的特性识别算式,进行运算,两个矩阵A(m,n),B(n,l)相乘,所需乘法次数为m*n*l。**本题的注意要点在两处,都属于中间值寄存器:*1.只用一个中间值寄存器时,切记要等到中间值参与的计算完成后再对其进行更新*2.本题中不可能只用到一个中间值寄存器,因为可能出现((中间值1)((中间值2)((中间值3)((中间值4)G))))的情况*  因为ACSII码的A从65开始在127处结束,所以这里的取了60个数组,中间值寄存器的大小为60减去需要输入的矩阵的数量n**先输入矩阵的多少,再输入矩阵,然后输入矩阵的运算式*9A 50 10B 10 20C 20 5D 30 35E 35 15F 15 5G 5 10H 10 20C                     0(AA)                  error(AB)                  10000(AC)                  error(A(BC))               3500((AB)C)               15000(((((DE)F)G)H)I)      40500(D(E(F(G(HI)))))      47500((D(EF))((GH)I))      15125*/#include<iostream>//用到栈时要有的头文件引用#include<stack>using namespace std;int main(){//假定矩阵算式最长为10000char input[1000];//创建一个栈sstack<char>s;//M用于存放参与运算的矩阵的标记字符,均以A开始,最多有26个,第27个用于生成存放中间矩阵乘积结果的数组空间对应的字符//middle作为中间值寄存器使用,分别存放矩阵的行数和列数。char M[27],middle[2];//N中存放参与运算的矩阵以及中间矩阵乘积结果的行列数据,n中记录所需记录的矩阵数量,lenth中获取矩阵运算式的长度,i,j为帮助运算的变量//sign为运算标志,sign为0时表示此矩阵算式有结果,sign为1时表示此矩阵算式无结果,number中存放所需输出的矩阵算式中所进行的乘法次数int N[60][2],n,i=0,lenth,sign,number,j;//输入矩阵数量cin>>n;//根据矩阵数量n,通过while循环,循环创建矩阵数据while(i<n){cin>>M>>N[i][0]>>N[i][1];i++;}//通过while循环保证运算式的持续输入while(cin>>input){//每一次运算之前都需对着三个变量清零处理sign=0;number=0;j=0;//通过strlen函数让lenth中获取到用户输入的算式的长度lenth=strlen(input);//如果算式长度大于1,表示参与运算的为两个即以上矩阵数量,开始进行运算及判断if(lenth>1){//通过lenth以内的for循环对算式进行识别for(i=0;i<lenth;i++){//如果没有遇到后括号‘)’则入栈if(input[i]!=')'){s.push(input[i]);}//如果遇到后括号‘)’则连续进行三次出栈,分别是两个进行运算的矩阵符号和前括号‘(’else{//第一个要出栈的是右边的乘数,用栈顶s.top()赋值给middle[1]//由于矩阵乘法的特殊性左右乘数不要弄反middle[1]=s.top();//保存好右边的乘数,第一次出栈s.pop();//第二个要出栈的是左边的乘数,用栈顶s.top()赋值给middle[0]middle[0]=s.top();//保存好左边的乘数,第二次出栈s.pop();//此时栈顶为左括号‘(’,第三次出栈s.pop();//对保存好的两个乘数进行判断,如果左边矩阵的列数等于右边矩阵的行数,则可以进行运算if(N[middle[0]-'A'][1]==N[middle[1]-'A'][0]){//number中存放总共进行的乘法次数,切勿忘记自加number+=(N[middle[0]-'A'][0]*N[middle[0]-'A'][1]*N[middle[1]-'A'][1]);//数组N中第n+1个即第N[n]个为第一个由矩阵相乘的到的新矩阵,此时j=0N[n+j][0]=N[middle[0]-'A'][0];N[n+j][1]=N[middle[1]-'A'][1];//这第n+1个矩阵的表示符号由n+j+'A'的到通过M[26]获取为符号值M[26]=n+j+'A';//已生成一个乘积矩阵,j自增1j++;//将这个乘积矩阵的表示符号压栈s.push(M[26]);}//如果左边矩阵的列数不等于右边矩阵的行数则此运算式不能得到结果,运算标志sign赋值为1,并且退出循环else{sign=1;break;}}}}//如果运算式的长度为1,则说明不会有乘法运算进行,则乘法次数为零,输出0if(lenth==1){cout<<0<<endl;}//如果运算式的长度不为1,但是运算标志的值为1,则此运算不能成立,输出errorelse if(sign==1){cout<<"error"<<endl;}//如果运算式长度大于1,并且运算标志位0,即此运算成立,则输出运算次数number。else{cout<<number<<endl;}}return 0;}

0 0
原创粉丝点击