矩阵连乘问题

写给自己的话: 有时候虽然一道题懂做了,但是发现写解题报告时,要清楚把自己的思路描述出来却挺难的。做解题报告

不仅可以巩固、梳理知识,还可以加深理解。现在我还做得很不好, 一定要坚持! 加油! 


矩阵链乘问题:


例子:

(下面第二个{P1应该是P2)

void MatrixChain()  
{  
    int i, j, k, t;  

    for(i = 1; i <= n; i++)  
        m[i][i] = 0;    //对角线赋值为0,是因为1个矩阵需做0次相乘  

	for(r=2; r<=n; ++r){
		for(i=1; i<=n-r+1; ++i){
			j=i+r-1;
			dp[i][j] = INF;  // INF表示一个很大的数
			for(k=i; k<=j-1; ++k){
				int temp=dp[i][k]+dp[k+1][j]+arr[i-1]*arr[k]*arr[j]; // arr数组的下标从0开始 。如果从1开始,各加1   
				if(temp

RQNOJ 矩阵链乘法 http://www.rqnoj.cn/Problem_652.html

题目描述

我们都知道矩阵乘法:给定两个矩阵A和B,若A是n*r的矩阵,B是r*m的矩阵,则A*B的结果C是一个n*m的矩阵,且c[i,j]=∑a[i,k]*b[k,j],其中1<=k<=r。很显然,求出每个C[i,j]的过程中,我们都做了r次标量乘法。因此,总的标量乘法次数是n*m*r。
矩阵乘法满足结合律。换句话说,即使乘的顺序不同,结果都是相同的。例如,四个矩阵相乘,会有五种不同的顺序:
(A1(A2(A3A4)))
(A1((A2A3)A4))
((A1A2)(A3A4))
((A1(A2A3))A4)
(((A1A2)A3)A4)
但是,不同的顺序会导致不同的效率——本题中,我们希望将给定的矩阵乘起来,并且使得总的标量乘法次数最少。注意,本题中给定的矩阵可以看作是环形的——第一个和最后一个矩阵可以相乘!为了满足矩阵乘法的合法性,输入数据保证对于任意相邻的矩阵,它们相邻的维数一定相等。

【数据规模和约定】
n<=100
所有矩阵的行、列数都是不超过1000的正整数。

输入格式

第一行一个整数n,表示矩阵个数。
接下来n行,每行两个整数,表示这个矩阵的行数和列数。

输出格式

一个整数,表示最少乘法次数。

4
2 3
3 5
5 10
10 2

样例输出

142

/*
这一题和另外一题《能量项链》完全相同。
注意这第一个矩阵可以和最后一个相连, 相当于是一个环
处理环时,把这个环断掉,变成一条线,然后复制元素增长
处理时,它有不同个起点。
分别比较每个起点的结果,取其中最小的就是答案

 */


#include
#include
#define MAXN 250
#define INF 2147483646

int arr[MAXN];
int dp[MAXN][MAXN];

int main()
{
//	freopen("input.txt","r",stdin);
	int i,n,a,b,r,j,k,s;
	scanf("%d",&n);

	for(i=1; i<=n; ++i){
		scanf("%d %d",&arr[i],&a);
		arr[i+n]=arr[i]; // 复制元素
	}
	int ans=2147483646;
	for(s=0; s<=n-1; ++s){   // 起点位置
		memset(dp,0,sizeof(dp));
		for(r=2; r<=n; ++r){
			for(i=1; i<=n-r+1; ++i){
				j=i+r-1;
				dp[i][j]=INF;
				for(k=i; k<=j-1; ++k){
					int temp=dp[i][k]+dp[k+1][j]+arr[i+s]*arr[k+1+s]*arr[j+1+s];
					if(temp


UVA  10003 - Cutting Sticks

/*
这题也是矩阵连乘问题
关键在于把砍木棍的过程逆过来看。
即现在不是砍,而是把n段不同长度的木棍连成一整段
每次两根木棍连接成一段时,这两根木棍的长度之和就是这次的费用。

*/

#include
#include
#define MAXN 55
#define INF 2147483646

int len[MAXN],arr[MAXN];
int dp[MAXN][MAXN];

int main()
{
 	freopen("input.txt","r",stdin);
	int l,n,i,j,k,r;
	while(scanf("%d",&l),l){
		scanf("%d",&n);
		len[0] = 0, arr[0]=0;
		for(i=1; i<=n; ++i){
			scanf("%d",&arr[i]);
			len[i] = arr[i]-arr[i-1];
		}
		arr[n+1]=l;
		len[n+1] = l-arr[n];

		memset(dp,0,sizeof(dp));
		for(r=2; r<=n+1; ++r){
			for(i=1; i<=n+1-r+1; ++i){
				j=r+i-1;
				dp[i][j] = INF;
				for(k=i; k<=j-1; ++k){
					int temp=dp[i][k]+dp[k+1][j]+arr[j]-arr[i-1];  
					if(temp

[NOI1995]石子合并

/*
	[NOI1995]  石子合并

这题和上一题的木棍本质上都是一样的,只是石堆的放置是环状的。
处理一下把环状变成链状就可以了
然后比较各个不同起点得到答案
*/

#include
#include
#define MAXN 105
#define oo 1147483646

int arr[MAXN];
int dp_min[MAXN][MAXN];
int dp_max[MAXN][MAXN];

inline int sum(int start,int end){
	int sum=0;
	for(int i=start; i<=end; ++i)
		sum += arr[i];
	return sum;
}


int main()
{
//	freopen("input.txt","r",stdin);

	int N,i,j,s,k,r;
	while(scanf("%d",&N)!=EOF){
		for(i=1; i<=N; ++i){
			scanf("%d",&arr[i]);
			arr[i+N]=arr[i];
		}

		memset(dp_min,0,sizeof(dp_min));
		memset(dp_max,0,sizeof(dp_max));

		int ans1=oo, ans2=-oo;
		for(s=0; s<=N-1; ++s){

			for(r=2; r<=N+1; ++r){
				for(i=1; i<=N-r+1; ++i){
					j=r+i-1;

					dp_min[i][j] = oo;
					dp_max[i][j] = -oo;
				
					int total=sum(i+s,j+s);

					for(k=i; k<=j-1; ++k){
						int t1=dp_min[i][k]+dp_min[k+1][j]+total;
						int t2=dp_max[i][k]+dp_max[k+1][j]+total;
						if(t1dp_max[i][j]) dp_max[i][j]=t2;
					}
				}
			}
			if(dp_min[1][N]ans2) ans2=dp_max[1][N];
		}
		printf("%d\n%d\n",ans1,ans2);
	}
	return 0;
}



矩阵链乘的打印:


FILE 348 - Optimal Array Multiplication Sequence 9516
39.84%
2895
85.60%
#   Problem Verdict Language Run Time Submission Date
10095483 348 Optimal Array Multiplication Sequence Accepted C++ 0.060 2012-05-10 05:39:06
/*
UVa  348	Optimal Array Multiplication Sequence

矩阵连乘 + 打印

*/

#include
#include
#include
using namespace std;
#define MAXN 15
#define INF 1073741824

int m[MAXN];
int dp[MAXN][MAXN],s[MAXN][MAXN];


// 递归打印
void Print(int i,int j){
	if(i==j){
		printf("A%d",i);
		return ;
	}
	else{
		printf("(");			
		Print(i,s[i][j]);
		printf(" x ");		
		Print(s[i][j]+1,j);
		printf(")");
	}
}

int main()
{
 	freopen("input.txt","r",stdin);
	int n,r,b,i,j,k,cas=1;
	while(scanf("%d",&n)!=EOF){
		if(!n) break;

		printf("Case %d: ",cas++);

		for(i=0; i



——      生命的意义,在于赋予它意义。 

                   原创  http://blog.csdn.net/shuangde800  , By   D_Double






你可能感兴趣的:(资料学习,动态规划,解题报告)