说明
乘法游戏是在一行牌上进行的。每一张牌包括了一个正整数。在每一个移动中,玩家拿出一张牌,得分是用它的数
字乘以它左边和右边的数,所以不允许拿第1张和最后1张牌。最后一次移动后,这里只剩下两张牌。目标是使得分
的和最小。例如,如果数是10 1 50 20 5,依次拿1、20、50,总分是10 * 1 * 50 + 50 * 20 * 5+10 * 50 * 5=8000而拿50、20、1,总分是1 * 50 * 20+1 * 20 * 5 + 10 * 1 * 5=1150
输入格式
输入第一行包括牌数(2<=n<=100),第二行包括N个1-100的整数,用空格分开。
输出格式
最小得分
样例
输入数据 1
6
10 1 50 50 20 5
Copy
输出数据 1
3650
思路
首先,要明确一点,这个游戏不好玩这道题不好用暴力。
于是,可以发现,这道题能用合并类Dp来写。
怎么写呢?
看看题目,我们发现,只要将两个合并的所有可能写出来,就能得到三个的可能,这样就可以使用递推!!!
然后,再总结出核心公式:
for(int i=1;i<=n-2;i++){
f[i][i+2]=z[i]*z[i+1]*z[i+2];
}
for(int i=4;i<=n;i++){
for(int j=1;j<=n-i+1;j++){
long long zs=i+j-1,as=1e9+32;
for(int k=j+1;k<=zs-1;k++){
//long long ;
as=min(as,f[j][k]+f[k][zs]+z[j]*z[zs]*z[k]);
//cout<<as<<" ";
}
f[j][zs]=as;
}
}
就可以做出题目了。
代码见下:
#include<bits/stdc++.h>
using namespace std;
long long mo=1e9+7,f[1005][1005],ld[1000405],lk=0,n,m,z[14045];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>z[i];
}
for(int i=1;i<=n-2;i++){
f[i][i+2]=z[i]*z[i+1]*z[i+2];
}
for(int i=4;i<=n;i++){
for(int j=1;j<=n-i+1;j++){
long long zs=i+j-1,as=1e9+32;
for(int k=j+1;k<=zs-1;k++){
//long long ;
as=min(as,f[j][k]+f[k][zs]+z[j]*z[zs]*z[k]);
//cout<<as<<" ";
}
f[j][zs]=as;
}
}
cout<<f[1][n]<<endl;
return 0;
}
但还可以进一步简化核心代码:
for(int i=3;i<=n;i++){
for(int j=1;j<=n-i+1;j++){
long long zs=i+j-1,as=1e9+32;
for(int k=j+1;k<=zs-1;k++){
//long long ;
as=min(as,f[j][k]+f[k][zs]+z[j]*z[zs]*z[k]);
//cout<<as<<" ";
}
f[j][zs]=as;
}
}
代码见下:
#include<bits/stdc++.h>
using namespace std;
long long mo=1e9+7,f[1005][1005],ld[1000405],lk=0,n,m,z[14045];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>z[i];
}
for(int i=3;i<=n;i++){
for(int j=1;j<=n-i+1;j++){
long long zs=i+j-1,as=1e9+32;
for(int k=j+1;k<=zs-1;k++){
//long long ;
as=min(as,f[j][k]+f[k][zs]+z[j]*z[zs]*z[k]);
//cout<<as<<" ";
}
f[j][zs]=as;
}
}
cout<<f[1][n]<<endl;
return 0;
}