动态规划算法之最大k乘积问题

问题描述

在这里插入图片描述

题目分析

这是一道典型的动态规划问题,我们假设L(s,t)为I的从s位开始的t位数字组成的十进制数。f(i,j)表示L(0,L)的最大j乘积,则f(i,j)具有最优子结构性质。计算f(i,j)的动态规划递归式如下:
f(i,j) = max{f(k,j-1) * L(k,i-k)} (1 <= k <= i)
这个式子的意思是我们假设在第k位之前的最大j-1乘积是f(k,j-1),所以我们只需要乘上第j个数字,即可 完成最大j乘积,因此从k位开始的i-k个数字组成的整体数字就是我们的第j个数字,二者相乘,求出最大即可。

代码

O#include <iostream>
#include <fstream>
using namespace std;
void solve(int n,int m)
{
    int i,j,k;
    int temp,maxt,tk;
    for(i = 0;i <= n;i++)
    {
    	//f[i][1]就表示一个数字自己做乘积,也就是这个数字本身了。
        f[i][1] = conv(0,i);
    }
    //最大乘积数,即我们要求最大的m乘积问题,所以应该从最大二乘积开始遍历
    for(j = 2;j <= m;j++)
    {
    	//要查找的字符串的末尾,由于字符串整个长度为n,所以要查找的末尾最大为n
    	//又因为如果要分成j个最大乘积,字符串至少有j个字符
    	//所以将要被查找的字符串的长度至少为j,因此字符串的末尾长度至少为j
        for(i = j;i <= n;i++)
        {
            for(k = 1,temp = 0;k < i;k++)
            {
                maxt = f[k][j-1] * conv(k,i-k);
                if(temp < maxt)
                {
                    temp = maxt;
                    tk = k;
                }
            }
        }
        f[i][j] = temp;
        //记录长度为i的字符串达到最大j乘积时的分割位置,即从哪里分割开第j-1个乘即和第j个乘积
        ka[i][j] = tk;
    }
}
//将字符串中从i开始的j个字符转换为数字
int conv(int i,int j)
{
    string str1 = str.substr(i,j);
    //c_str以char的形式传回string串,所以某个函数需要char做参数可以使用c_str
    return atoi(str1.c_str);
}
//输出函数
void out(int n,int m )
{
    ofstream cout("out.txt");
    cout<<f[n][m]<<endl;
    for(int i =m,k = n;i >= 1 &&k > 0;k = ka[k][i],i--)
    {
        cout<<"f["<<k<<"]["<<i<<"]="<f[k][i]<<endl;
    }
}
int main()
{
    int n,m;
    ifstream cin1("in.txt");
    cin1>n>>m;
    if((n < m || (n == 0)))
    {
        cout<<0<<endl;
        return;
    }
    cin1>>str;
    if(n != str.size())
    {
        cout<<0<<endl;
        return;
    }
    f.resize(n+1,m+1);
    ka.resize(n+1,m+1);
    solve(n,m);
    out(n,m);
    return 0;
}

总结

时间复杂度为O(mn^2)

发布了60 篇原创文章 · 获赞 2 · 访问量 1050

猜你喜欢

转载自blog.csdn.net/weixin_44755413/article/details/105643578