Saki也想要变强之Saki的一日一题(2)
day 2
题目:
用加括号的方式给出最优的矩阵相乘方案
输入:
多组数据输入
第一行一个整数 n,表示矩阵链的长度(1<=n<=300)
接下来一行n+1个数表示这些矩阵的行数和列数
别问我为什么只有n+1个数,每相邻的两个数表示一个矩阵的大小
输出:
对于每组数据,输出两行,第一行为计算次数,第二行为计算方案,用加括号的方式给出最优的矩阵相乘方案
如果不幸最优方案不唯一,选择优先计算左边的矩阵
代码:
include<stdio.h>
include<limits.h>
include<stdlib.h>
int a[1000],m[1000][1000],s[1000][1000];
int max(int a, int b){
if(a>b)
return a;
else return b;
}
void move(int i,int j){
if(i==j){
printf("A%d", i);
}
else{
printf("(");
move(i, s[i][j]);
move(s[i][j] + 1, j);
printf(")");
}
}
int main()
{
int n,i,l,j,k,temp;
while (~scanf("%d",&n)){
for (i = 0; i <= n;i++)
{
scanf("%d", &a[i]);
}
for (i = 1; i <= n;i++){
m[i][i] = 0;
}
for (l = 2; l <= n;l++){
for (i = n-l+1; i >= 1;i--)
{
j = i + l - 1;
m[i][j] = INT_MAX;
for (k = j-1; k >= i;k--){
temp = m[i][k] + m[k + 1][j] + a[i - 1] * a[k]*a[j];
if(temp<m[i][j]){
m[i][j] = temp;
s[i][j] = k;
}
}
}
}
printf("%d\n", m[1][n]);
move(1, n);
printf("\n");
}
}
心得明天~~
心得:
很简单的矩阵链乘法问题,但我还是WA了几次,原因是我按算法导论上的思路写的代码,而本题要求若最优方案不唯一,选择优先计算左边的矩阵。而算法导论上的是优先计算右边的矩阵~~所以我们要小小的改一改。
先说具体思路,先定义两个矩阵m,s。m记录矩阵i——j相乘最少步骤数,而此时将矩阵分成i—k与k+1—j两部分相乘获得最优解,s则用来记录k的值。
代码中有三层循环,前两层循环的目的是,先后另j=i+1,j=i+2。。。依次求出每一个子问题。第三层循环时在i—j-1中依次取k的值,以此找出最优解。
最后通过move函数输出,如果i=j,输出Ai即可,若i!=j,输出最优方案,即i—k与k+1—j。
那么我们怎么选择优先计算左边的矩阵呢?只要我们把k的循环改成从右到左即可,这样若有多组最优解,划分k一定是右边那个,这样就达到了优先计算左边的效果。


浙公网安备 33010602011771号