最优矩阵链乘
上面说的计算量其实是乘法的计算量,并没有关注加法!因为加法的计算量,加法其实是和乘法相关的,乘法越少,加法也就越少
【分析】
结合《算法竞赛入门经典(第2版)》分析,突破点是最后一次乘法!不妨设Ai到Aj矩阵相乘,最后一次乘法的前k个矩阵之积和后面的矩阵之积相乘。row[i],col[i]表示第i个矩阵的行和列。那么,
状态:dp[i][j]表示Ai到Aj矩阵相乘的最小计算量
状态转移:dp[i][j]=min{dp[i][k]+dp[k+1][j]+row[i]*col[k]*col[j]}
Optimal Array Multiplication Sequence UVA - 348
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=15;
const int INF=(1<<30);
int n;
int row[maxn],col[maxn];
int kase=0;
int d[maxn][maxn];
int path[maxn][maxn];
int dp(int i,int j){
int &ans=d[i][j];
if(ans!=-1) return ans;
ans=INF;
for(int k=i;k<j;k++){
//用tmp接收一下,不要把这个写到if语句里面判断,减少递归调用时间消耗
int tmp=dp(i,k)+dp(k+1,j)+row[i]*col[k]*col[j];
if(ans>tmp){
ans=dp(i,k)+dp(k+1,j)+row[i]*col[k]*col[j];
path[i][j]=k;
}
}
return ans;
}
void print(int i,int j){
if(i==j){
cout<<"A"<<i;
return ;
}
cout<<"(";
for(int k=1;k<j;k++){
if(path[i][j]==k){
print(i,k);
cout<<" x ";//这两个空格也是坑
print(k+1,j);
break;
}
}
cout<<")";
}
int main()
{
while(cin>>n && n){
for(int i=1;i<=n;i++){
cin>>row[i]>>col[i];
}
memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++) d[i][i]=0;
dp(1,n);
cout<<"Case "<<++kase<<": ";
print(1,n);
cout<<endl;
}
return 0;
}
Multiplication Puzzle POJ - 1651
【分析】
这道题也是最优矩阵链乘,直接用上题的代码,稍微修改一下即可
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=105;
const int INF=(1<<30);
int n;
int row[maxn],col[maxn];
int d[maxn][maxn];
int a[maxn];
int dp(int i,int j){
int &ans=d[i][j];
if(ans!=-1) return ans;
ans=INF;
for(int k=i;k<j;k++){
ans=min(dp(i,k)+dp(k+1,j)+row[i]*col[k]*col[j],ans);
}
return ans;
}
int main()
{
while(cin>>n){
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n-1;i++){
row[i]=a[i];
col[i]=a[i+1];
}
memset(d,-1,sizeof(d));
for(int i=1;i<=n;i++) d[i][i]=0;
cout<<dp(1,n-1)<<endl;
}
return 0;
}