矩阵链乘法

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

void print(vector<char> &vcname, vector<vector<int>> &virecord, int b, int e){//包含e
    if(b==e)
        cout<<vcname[b];
    else{
        /*
        cout<<"(";
        print(vcname,virecord,b,virecord[b][e]);
        print(vcname,virecord,virecord[b][e]+1,e);
        cout<<")";
        */
        if(b<virecord[b][e]){
            cout<<"(";
            print(vcname,virecord,b,virecord[b][e]);
            cout<<")";
        }
        else
            print(vcname,virecord,b,virecord[b][e]);
        if(virecord[b][e]+1<e){
            cout<<"(";
            print(vcname,virecord,virecord[b][e]+1,e);
            cout<<")";
        }
        else
            print(vcname,virecord,virecord[b][e]+1,e);
    }
}

void method1(vector<pair<int,int>> vpii,vector<char> &vcname, vector<vector<int>> vvi){
    //方法一:
    //这个相当于以步长作为界限,如果当前步长前面的结果已知,那么就可以依据之前的步长的结果求出当前步长下的最优结果。
    cout<<"method1: "<<endl;
    int n=vpii.size();
    vector<vector<int>> virecord;//记录分裂点
    for(int i=0;i<n;i++)
        virecord.push_back(vector<int>(n,-1));
    for(int step=2;step<=n;step++){//注意这里的下标
        //计算到当前步长时,小于此步长的组合结果都算出来了,也就是vvi[i][k]与vvi[k+1][j]都已知了。
        for(int i=0;i<=n-step;i++){//当i=n-step时,j=i+step-1=n-1
            int j=i+step-1;//当前步长,当前起始i时的最大矩阵下标
            for(int k=i;k<j;k++){
                int itp=vvi[i][k]+vvi[k+1][j]+vpii[i].first*vpii[k].second*vpii[j].second;
                if(vvi[i][j]>itp){
                    vvi[i][j]=itp;
                    virecord[i][j]=k;//记录分裂信息
                }
            }
            cout<<vvi[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<vvi[0][vpii.size()-1]<<endl;
    print(vcname,virecord,0,n-1);//打印矩阵结合顺序
    cout<<endl;
}

void method2(vector<pair<int,int>> vpii,vector<char> &vcname, vector<vector<int>> vvi){
    //方法二
    //这个结构顺序安排的非常巧妙
    //这个相当于以某个下标为界限,如果之前的数列的最优结果已经求出来了,那么就可以依据之前的数列的最优结果求出当前下标为止的最优结果。
    cout<<"method2: "<<endl;
    int n=vpii.size();
    vector<vector<int>> virecord;//记录分裂点
    for(int i=0;i<n;i++)
        virecord.push_back(vector<int>(n,-1));
    for(int j=1;j<n;j++){//当计算到j时,k<j,vvi[i][k]已经算出来了
        for(int i=j-1;i>=0;i--){//当计算到i时,k>i,vvi[k][j]已经算出来了。
            for(int k=i;k<j;k++){
                int itp=vvi[i][k]+vvi[k+1][j]+vpii[i].first*vpii[k].second*vpii[j].second;
                if(itp<vvi[i][j]){
                    vvi[i][j]=itp;
                    virecord[i][j]=k;//记录分裂信息
                }
            }
            cout<<vvi[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<vvi[0][vpii.size()-1]<<endl;
    print(vcname,virecord,0,n-1);//打印矩阵结合顺序
    cout<<endl;
}

int main(){
    vector<pair<int,int>> vpii;
    vpii={{30,35},{35,15},{15,5},{5,10},{10,20},{20,25}};
    vector<char> vcname;
    vcname={'A','B','C','D','E','F'};
    vector<vector<int>> vvi;
    for(int i=0;i<vpii.size();i++){
        vvi.push_back(vector<int>(vpii.size(),INT_MAX));
        vvi[i][i]=0;
    }
    method1(vpii,vcname,vvi);
    method2(vpii,vcname,vvi);
}
/*
http://blog.csdn.net/chenwenshi/article/details/6056015 这里说methd2是自顶向下,其实我感觉不是.
 其实两种思路都是自底向上,毕竟动态规划依赖子问题的最优解,只是两种方法划分子问题的方式不同。
 对于第一种方法:相当于以步长作为界限,如果当前步长前面的结果已知,那么就可以依据之前的步长的结果求出当前步长下的最优结果。
 对于第二种方法:相当于以某个下标为界限,如果之前的数列的最优结果已经求出来了,那么就可以依据之前的数列的最优结果求出当前下标为止的最优结果。
*/

猜你喜欢

转载自blog.csdn.net/o1101574955/article/details/75896593