zoukankan      html  css  js  c++  java
  • 矩阵连乘-动态规划

    问题描述

    给定n个矩阵({ A_1,A_2,A_3 dots, A_n }),其中(A_i)(A_{i+1})是可乘的,(i=1,2,3,dots, n-1)。考察这n个矩阵的连乘积(A_1A_2dots A_n),由于矩阵乘法满足结合律,所以计算矩阵的连乘可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。

    分析最优解结构

    dp[i][j](A_iA_{i+1}dots A_j)的最少乘积次数,并设(A_iA_{i+1}dots A_j)的最优计算次序从矩阵(A_k)(A_{k+1})之间断开,(ileq k < j)。那么加括号方式为(((A_iA_{i+1}dots A_k)(A_{k+1}dots A_{j-1}A_{j})))
    最优总计算量dp[i][j] = dp[i][k] + dp[k+1][j] + A[i:k]与A[k+1:j]乘积次数。其中A[i:k](A_iA_{i+1}dots A_k)得到的矩阵,A[k+1][j]同理。
    得出,矩阵连乘计算次序的最优解包含着其子问题的最优解。这种性质称为最优子结构性质。

    解题思路

    我们首先默认矩阵的索引从0开始,即(A_0A_1dots A_{n-1})
    创建一个数组dpdp[i][j]用来保存矩阵(A_idots A_j)的最优乘积次数,在创建一个数组p,用来保存所有矩阵的行列数目。例如上图中的例子,它们的行列数目在p中保存为[50,10,40,30,5]
    根据最优解结构的分析,可以得出动态规划的递推公式为:

    [dp[i][j] = egin{cases} 0 & ext{i = j} \ min_{ileq k leq j}(pd[i][k]+pd[k+1][j]+p_ip_{k+1}p_{j+1}) & ext{i $<$ j} end{cases} ]

    为了保证每次计算dp[i][j]时,任意的pd[i][k]pd[k+1][j]都已经得到结果,我们需要首先计算主对角线,然后再依次计算次对角线。

    目前我们只是知道了最优计算次数,但是还不知道如何加括号。下面我们再定义一个数组sdp形状相同,用来记录矩阵(A_idots A_j)之间的最优分割位置k。最后通过递归找到最优加括号位置。

    C++代码

    #include<iostream>
    #include<vector>
    using namespace std;
    
    void Traceback(int i,int j,vector<vector<int> >s)
    { 
    	if(i==j) return;
    	Traceback(i,s[i][j],s);
            Traceback(s[i][j]+1,j,s);
            cout<<"Multiply A"<<i<<","<<s[i][j];
            cout<<"and A"<<s[i][j]+1<<","<<j<<endl;
    }
    
    int main()
    {
    	int N; 
    	cout<<"请输入矩阵个数:"; 
    	cin>>N;
    	vector<vector<int> >dp(N+1, vector<int>(N+1, 0));
    	vector<vector<int> >s(N+1, vector<int>(N+1, -1));
    	vector<int>p(N+1);
    	
    	cout<<"输入每个矩阵的行列数:";
    	for(int i=0; i<=N; i++)
    		cin>>p[i];
    	
    	for(int n=1; n<N; n++)
    	{
    		int i = 0, j = n;
    		while(j<N && i<N)
    		{
    			dp[i][j] = 0x7fffffff;
    			int val;
    			for(int k=i; k<=j; k++)
    			{
    				val = dp[i][k]+dp[k+1][j]+p[i]*p[k+1]*p[j+1];
    				if(val < dp[i][j])
    				{
    					dp[i][j] = val; 
    					s[i][j] = k;
    				}
    			}
    			i++; j++;
    		}
    	}
    	Traceback(0, N-1, s);
    	
    	cout<<dp[0][N-1];
    	return 0;
    }
    
  • 相关阅读:
    【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie
    【ASP.NET Web API教程】3.3 通过WPF应用程序调用Web API(C#)
    【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器
    【翻译】ASP.NET Web API是什么?
    【ASP.NET Web API教程】2.3.6 创建产品和订单控制器
    《精通ASP.NET MVC 3框架》译者序
    【ASP.NET Web API教程】3 Web API客户端
    委托、事件与匿名方法 — 学习委托最好的资料
    【ASP.NET Web API教程】2.3.3 创建Admin控制器
    【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI
  • 原文地址:https://www.cnblogs.com/xxmmqg/p/12811385.html
Copyright © 2011-2022 走看看