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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章