編程作業三

[算法導論] 編程作業三:矩陣鏈乘法與最大子數組

PB15000105 肖映泰

一、作業任務

1.採⽤用動態規劃算法編程實現矩陣連乘的最優括號化方案,並輸出最優括號化方案

2.採用分治法和貪心算法實現最大子數組

二、算法原理

矩陣鏈乘法

給定n個矩陣的鏈<A1,A2,...,An> ,矩陣的規模爲pi1×pi(1in) ,求完全括號化方案,使得計算乘積A1A2...An 所需要標量乘法的時間最少

步驟1:最優括號化方案的結構特徵

​ 假設AiAi+1...Aj 的最優括號化方案的割點在AkAk+1 之間,那麼子問題分解爲獨立求解AiAi+1...Ak 的最優括號化方案,與Ak+1Ak+2...Aj 的最優括號化方案

步驟2:一個遞歸求解方案

​ 令m[i,j] 表示計算矩陣所需要標量乘法次數的最小值,則可以遞歸定義m[i,j] 如下

m[i,j]={(3)0,i=j(4)minik<jm[i,k]+m[k+1,j]+pi1pkpj,i<j

​ 令s[i,j] 保存AiAi+1...Aj 最優括號化方案的分割點位置k

步驟3:計算最優代價

​ 可以證明算法的運行時間爲Ω(n3)

步驟4:構造最優解

​ 利用表格s[i,j] 即可遞歸地輸出最優解

最大子數組

分治法

遞歸求解

A[low...high] 的任何連續子數組A[i,j] 所處的位置必然是一下集中情況之一

完全位於子數組A[low...mid]

完全位於子數組A[mid+1…high]中

跨越了中點

對於第三種情況可以使用O(n) 的算法FMCS求解

對於前兩種情況,繼續採用分治法遞歸求解

貪心算法

從A[1]開始,M記錄當前子數組的和,Mr記錄從開始至今的最大子數組的和。

一旦M大於Mr,將Mr設置爲M並記錄當前子數組的下標[low,high]

若M小於0,則將當前子數組置爲0,重新開始。

三、性能分析

正確性驗證

利用書本例子驗證算法的正確性

1.矩陣鏈乘法

調用test.h中的testMCO()函數,得到書本P214頁同樣的輸出

2.最大子數組

分別調用testFMS()和testGreedy()得到與書本P39相同的輸出
這裏寫圖片描述這裏寫圖片描述

性能分析

隨機產生100,200,300大小的數組,範圍在[-100,100)之間,調用時間測試算法,輸出結果
這裏寫圖片描述

從圖中所得的數據可以粗略估計

MCO:O(n3)

分治法:O(nlg2(n))

貪心算法:O(n)

四、實驗總結

本次實驗學習到了一些新的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)內的隨機數
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章