您的位置:首页 > 其它

最佳加法表达式

2020-04-22 16:55 267 查看

最佳加法表达式

题目描述
有一个由1…9组成的数字串.问如果将m个加号插入到这个数字串中,在各种可能形成的表达式中,值最小的那个表达式的值是多少。
输入:
5 3
1 2 3 4 5
输出:
24

我们一开始可以采用递归的思路来进行思考。
我们先考虑,最右边的加号放在哪里?

假设数字字符2长度为n,最右边的加号放在第i个数字的后边.
那么现在最小值就是在前i个数字中插入m-1个加号后所能形成的最小值.
那么现在就是减而治之的递归思路就完成了(分解为规模更小的子问题来解决)

这也恰恰满足我们的最优子结构和无后效性

V(m,n)表示前n个数组当中插入m个加号所形成表达式最小值

下面借用以下人家的分析:
设V(m,n)表示在n个数字中插入m个加号所能形成
的表达式最小值,那么:
if m = 0
V(m,n) = n个数字构成的整数
else if n < m + 1
V(m,n) = ∞(不是所求就是最大的)
else
V(m,n) = Min{ V(m-1,i) + num(i+1,n) } ( i = m … n-1)
num(i,j)表示从第i个数字到第j个数字所组成的数。数字编号从1开始算。此操作复杂度是O(j-i+1),为了节省时间我们预处理num(i,j)(就是什么都不干之前把这些值全部算出来)
总时间复杂度:O(mn^2) .

有的题目需要用到高精度模板来进行计算了(long long无法承受得住的时候)高精度模板可以参考我教主的序列的文章

这里我想说的是,你一旦用高精度模板,那么将会变成O(mn^3),应为多了n个元素的数组,你每次操作数组都是O(n)的

递归型代码

#include <iostream>//最佳加法表达式
#include <cstring>
#include <algorithm>
#include  <cstdio>
const int INF=9999999;
int a[1010],num[1010][1010];
using namespace std;

int V(int m,int n)
{//状态转移方程
if(m==0)
return num[1][n];
else if(n<m+1)//加号多了
return INF;
else
{
int t = INF;
for(int i = m;i <= n-1;i++)
t = min(t, V(m-1,i)+num[i+1][n]);
return t;
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))//就是当没有输入的时候退出循环
{
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=n;++i)//预处理,节省时间
{
num[i][i]=a[i];//只有一个数组
for(int j=i+1;j<=n;++j)
{
num[i][j]=num[i][j-1]*10+a[j];
}
}
cout<<V(m,n)<<endl;

}
return 0;
}

递推型的可以自己想一下哦

递推型

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;//无穷大
const int N=1010;
int a[N],num[N][N],dp[N][N];
//a
里面是存数字串
//num[i][j]表示数字串a
的第i位到第j位之间的数字串表示的数组
int main(){
int n,m;
while(scanf("%d %d",&n,&m)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
//预处理,计算i到j数字串组成的数字
for(int i=1;i<=n;i++){
num[i][i]=a[i];//只有一个数字
for(int j=i+1;j<=n;j++){
num[i][j]=num[i][j-1]*10+a[j];
}
}
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
dp[0][i]=num[1][i];//无加号时
}
//这里n可以写在m前面。要加一个限制条件n>m,好麻烦,所以m在前且n=m+1
//这里k的取值范围就是m到n,k表示在第k个数后面插入加号
for(int i=1;i<=m;i++)
for(int j=i;j<=n;j++)
for(int k=i;k<=j;k++)
dp[i][j]=min(dp[i][j],dp[i-1][k]+num[k+1][j]);
cout<<dp[m][n]<<endl;
}
}

学会程序和算法,走遍天下都不怕

广西桂林

  • 点赞
  • 收藏
  • 分享
  • 文章举报
爱笑的Gary哥 发布了21 篇原创文章 · 获赞 6 · 访问量 654 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: