[算法導論] 編程作業三:矩陣鏈乘法與最大子數組
PB15000105 肖映泰
一、作業任務
1.採⽤用動態規劃算法編程實現矩陣連乘的最優括號化方案,並輸出最優括號化方案
2.採用分治法和貪心算法實現最大子數組
二、算法原理
矩陣鏈乘法
給定n個矩陣的鏈 ,矩陣的規模爲 ,求完全括號化方案,使得計算乘積 所需要標量乘法的時間最少
步驟1:最優括號化方案的結構特徵
假設 的最優括號化方案的割點在 和 之間,那麼子問題分解爲獨立求解 的最優括號化方案,與 的最優括號化方案
步驟2:一個遞歸求解方案
令 表示計算矩陣所需要標量乘法次數的最小值,則可以遞歸定義 如下
令 保存 最優括號化方案的分割點位置k
步驟3:計算最優代價
可以證明算法的運行時間爲
步驟4:構造最優解
利用表格 即可遞歸地輸出最優解
最大子數組
分治法
遞歸求解
的任何連續子數組 所處的位置必然是一下集中情況之一
完全位於子數組 中
完全位於子數組A[mid+1…high]中
跨越了中點
對於第三種情況可以使用 的算法FMCS求解
對於前兩種情況,繼續採用分治法遞歸求解
貪心算法
從A[1]開始,M記錄當前子數組的和,Mr記錄從開始至今的最大子數組的和。
一旦M大於Mr,將Mr設置爲M並記錄當前子數組的下標 。
若M小於0,則將當前子數組置爲0,重新開始。
三、性能分析
正確性驗證
利用書本例子驗證算法的正確性
1.矩陣鏈乘法
調用test.h中的testMCO()函數,得到書本P214頁同樣的輸出
2.最大子數組
分別調用testFMS()和testGreedy()得到與書本P39相同的輸出
性能分析
隨機產生100,200,300大小的數組,範圍在[-100,100)之間,調用時間測試算法,輸出結果
從圖中所得的數據可以粗略估計
MCO:
分治法:
貪心算法:
四、實驗總結
本次實驗學習到了一些新的c++使用技巧
1.vector表示矩陣
#include <iostream>
#include <vector>
void testVector()
{
//定義一個row*col的矩陣
int row=3;
int col=5;
//vec是一個向量,其中的元素爲向量,大小爲row,vec.size()==row;
//vec[0]是一個向量,大小爲col,vec[0].size()==col;
vector<vector<double> > vec(row,vector<double>(col,0.0));
}
2.返回多個值的方法
//有些時候用參數表返回值會顯得冗餘,可以採用返回指向結構體的指針的方法返回多個值
//這些值被存儲在一個結構體中
//當然也可以將結構體指針作爲參數傳入
struct Result
{
int left;
int right;
double sum;
};
Result* testResult()
{
Result *result= new Result;//new 之後記得要 delete
result->left=1;
result->right=10;
result->sum=100;
return result;
}
int main()
{
Result *result;
result=testResult();
delete result;
return 0;
}
3.產生隨機數
#include <iostream>
#include <vector>
//c++採用的是c的內置函數調用隨機數
#include <stdlib.h>
#include <time.h>
void testRand()
{
int N=100;//產生100個隨機數
vector<int> p(N , 0);
srand((unsigned)time(NULL));//設置隨機種子
for (int i = 0; i < N ; i++)
{
//rand()%(b-a)+a產生[a,b)內的隨機數
p[i] = rand()%(100-(-100))-100;//[-100,100)內的隨機數
}
}