ACM解题之(ZOJ 1094) Matrix Chain Multiplication

题目来源:

点击打开链接

题目翻译:

矩阵乘法问题是动态规划的典型例子。

假设你必须评估一个表达式,如A * B * C * D * E,其中A,B,C,D和E是矩阵。由于矩阵乘法是关联的,乘法运算的次序是任意的。但是,所需的基本乘法的数量很大程度上取决于您选择的评估顺序。 例如,设A是50 * 10矩阵,B是10 * 20矩阵,C是20 * 5矩阵。 计算A * B * C有两种不同的策略,即(A * B)* C和A *(B * C)。 第一个需要15000次基本乘法,但第二个只需要3500次。

你的工作是编写一个程序来确定给定评估策略所需的基本乘法的数量。

输入:

输入由两部分组成:矩阵列表和表达式列表。 输入文件的第一行包含一个整数n(1 <= n <= 26),表示第一部分中的矩阵数量。接下来的n行包含一个大写字母,指定矩阵的名称和两个整数,指定矩阵的行数和列数。 输入文件的第二部分严格遵守以下语法:

SecondPart = Line { Line } <EOF>
Line       = Expression <CR>
Expression = Matrix | "(" Expression Expression ")"
Matrix     = "A" | "B" | "C" | ... | "X" | "Y" | "Z"

输出:

对于在输入文件的第二部分中找到的每个表达式,如果由于不匹配的矩阵导致表达式的评估导致错误,则输出包含单词“error”的一行。否则,按照括号中指定的方式打印一行,其中包含评估表达式所需的基本乘法数。

例子:

输入

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

输出

0
0
0
error
10000
error
3500
15000
40500
47500
15125

解题:

此题,我用了stack和vector。首先定义一个矩阵结构,此结构包含两个数据:行数和列数。然后定义一个大小为26的矩阵数组,并且按ABC...这样排下去。根据输入改写数组里相应位置的数据;如:输入矩阵A的行列数,则修改vector[0]中的行列数。完成矩阵行列数的存储之后,就用stack来处理计算式子。逐一读取计算式子的字符,遇到字母就进栈,遇到左括号就什么事都不做,遇到右括号就出栈,然后进行计算判断。具体如下:

/*
c++/accepted
*/

#include<iostream>
#include<stack>
#include<string>
#include<vector>
using namespace std;

struct rc   //定义矩阵结构
{
	int r;
	int c;
};

int main() {
	stack<rc> st1;  //栈
	vector<rc> vec;   //数组
	for (int k = 0;k<26;k++)   //申请长度为26的矩阵数组
	{
		rc myrc;
		vec.push_back(myrc);
	}
	int n;
	cin >> n;
	while (n--)
	{
		int a, b;
		char ch;
		cin >> ch;  //矩阵名字
		cin >> a >> b;
		vec[(int)(ch) - 65].r = a;  //把行列数存到相应位置的矩阵那,A为vec[0],B为vec[1],以此类推
		vec[(int)(ch) - 65].c = b;
	}
	string s;//输入计算式子
	//cin >> s;
	while (cin>>s)
	{
		int num = 0;
		if (s.length() == 1)//如果计算式子长度为1,则相乘次数为0
		cout << 0 << endl;
		else
		{
			for (int i = 0;i<s.length();i++)
			{
				if (s[i] >='A'&&s[i]<='Z')  //遇到字母就进栈
					st1.push(vec[(int)(s[i]) - 65]);
				 	 
				else if (s[i] == ')')  //遇到右括号,出栈两个
				{
					rc myrc1 = st1.top();
					st1.pop();
					rc myrc2 = st1.top();
					st1.pop();
					if (myrc2.c != myrc1.r)//判断前面矩阵的列数是否等于后面矩阵的行数,如果不等,则error
					{
						cout << "error" << endl;
						num = 0;
						break;
					}
					else   //如果相等,就计算相乘次数(前行*前列*后列)
					{
						num = num + myrc2.r*myrc2.c*myrc1.c; //总次数=现次数+此次计算的次数
						myrc2.c = myrc1.c;
						rc myrc3;//经过一次计算后的结果矩阵(中间矩阵)
						myrc3.r = myrc2.r;
						myrc3.c = myrc1.c;
						st1.push(myrc3);//把中间矩阵进栈
					}
				}
				else//遇到左括号则什么都不做
				 ;
			}
		}
		if (num > 0)  //如果num为0,则可能为错,可能已经输出了(0)
			cout << num << endl; 
	}
	return 0;
}


【原创声明】转载请标明出处:https://www.cnblogs.com/surecheun/
原文地址:https://www.cnblogs.com/surecheun/p/9648977.html