动态规划法.md

动态规划算法

动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解决将由上一次子问题的解推出。
例题:
http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1017
题中所述的是在长度为N数字串中,添加K个乘号,将它分成K+1个部分,使得这K+1个部分的乘积最大
– 1.状态及状态转移方程(根据子问题定义状态
首先要定义一个“状态”来代表它的子问题,并且找到它的解。分解出子问题:把前i个数字分成j部分,计算最大值。我们用sum[i][j]表示从第i位到第j位组成的数字;f[i][j]表示把前i个数字分成j份乘积的最大值,要求出j个部分的乘积最大值,再次分解子问题:把前k个数字分成j-1个部分(1<=k<=i-1),可以得出状态转移方程:f[i][j]=max(f[i][j],f[k][j-1]*sum[k+1][i]);(建议自己动手画一下0~n简图,容易理解一些)
– 2.附加条件
需要根据实际情况考虑到可能存在的附加条件
例题中一定会有f[i][0]==sum[1][i];(1<=x<=N)
– 3.时间复杂度
根据程序实现,分析时间复杂度,本例:O(N^2*K)

总结:找到状态是关键,由此推出状态转移方程。学会将大规模问题分解为子问题,根据子问题定义状态

源码:

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
long long f[41][7];
long long sum[41][41];
char str[42];
#define max(a,b) (a>b? (a):(b))
int main()
{
int i, j;
int n, k;
cin >> n >> k;
for ( i = 1; i <= n; i++)
{
cin >> str[i];
}
for (i = 1; i <=n; i++)
{
for (j = i; j <= n; j++)
{
sum[i][j] = sum[i][j - 1] * 10 + str[j] - '0';//sum[i][j]代表第i位数到第j位数组成的数字
}
}
for (i = 1; i <= n; i++)
{
f[i][0] = sum[1][i];// f[i][j]代表把前i个数字分成j份乘积的最大值,j个乘号
}
for (j = 1; j <= k; j++)
{
for (i = 2; i <= n; i++)
{
for (int k = 1; k < i; k++)
f[i][j] = max(f[i][j], f[k][j - 1] * sum[k + 1][i]);
}
}
cout << f[n][k];
system("pause");
return 0;
}

附:
最长坡之问题http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1031

点赞