题目:
题目描述
给定n个矩阵{A1,A2,...,An},及m个矩阵连乘的表达式,判断每个矩阵连乘表达式是否满足矩阵乘法法则,如果满足,则计算矩阵的最小连乘次数,如果不满足输出“MengMengDa“。
输入
输入数据由多组数据组成(不超过10组样例)。每组数据格式如下:
第一行是2个整数n (1≤n≤26)和m(1≤m≤3),表示矩阵的个数。
接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数r和c,分别表示该矩阵的行数和列数,其中1<r, c<100。
第n+1行到第n+m行,每行是一个矩阵连乘的表达式(2<=矩阵个数<=100)。
输出
对于每个矩阵连乘表达式,如果运算不满足矩阵乘法法则的情况(即左矩阵列数与右矩阵的行数不同),则输出“MengMengDa”,否则输出最小矩阵连乘次数。
数据保证结果不超过1e9。
样例输入 Copy
3 2
A 10 100
B 5 50
C 100 5
ACB
ABC
样例输出 Copy
7500
MengMengDa
解析:
用dp[i][j]数组表示第i个矩阵到第j个矩阵连乘所需最小连乘次数
用p[]数组存储每个矩阵的行数和列数,如果矩阵能够连乘,则第i个矩阵的列数=第i+1个矩阵的行数,所以只需要用n+1个数字就能存储n个矩阵的行数和列数
可以把需要计算的矩阵拆分成两半,等于左边子区间最小连乘次数+右边子区间最小连乘次数+左右两个子区间连接起来需要的连乘次数。
假设第i个矩阵到第j个矩阵从第k个矩阵分成两半,那么dp[i][j]=dp[i][i] + dp[i+1][j] + p[i-1]*p[i]*p[j]
由此,只需要遍历k找到最佳的拆分位置即可
代码:
#include<iostream>
using namespace std;
int dp[110][110];
int p[110];
struct jz{
int x,y;
}m[26];
void solve()
{
string x;
cin>>x;
int size = x.size();
p[0] = m[x[0]-'A'].x;
for(int i=0;i<size-1;i++)
{
int a = x[i] - 'A';
int b = x[i+1] - 'A';
p[i+1] = m[a].y;
if(m[a].y!=m[b].x)
{
cout<<"MengMengDa"<<'\n';
return;
}
}
p[size] = m[x[size-1]-'A'].y;
for(int i=1;i<=size;i++)//初始化,单个矩阵
dp[i][i] = 0;
for(int r=2;r<=size;r++)//r个矩阵连乘
{
for(int i=1;i<=size-r+1;i++)//以第i个矩阵开头
{
int j = i+r-1;//以第j个矩阵结尾
dp[i][j] = dp[i][i] + dp[i+1][j] + p[i-1]*p[i]*p[j];
for(int k=i+1;k<j;k++)
{
int t = dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j];
if(t<dp[i][j])
dp[i][j] = t;
}
}
}
cout<<dp[1][size]<<'\n';
}
int main()
{
int n,mm;
while(cin>>n>>mm)
{
for(int i=0;i<n;i++)
{
char name;
int x,y;
cin>>name>>x>>y;
m[name-'A'].x = x;
m[name-'A'].y = y;
}
while(mm--)
solve();
}
}