求解整数拆分问题【动态规划】【备忘录】
问题描述
求讲正整数n无需拆分成最大数为k的拆分方案个数【f(n,k)】,要求所有的拆分方案不重复。
动态规划
f(n,k)满足动态规划问题的最优性原理、无后效性和有重叠子问题。
f(n,k):
- 当n=1或k=1,f(n,k)=1
- 当n<k,f(n,k)=f(n,n)
- 当n=k,将n拆分成一个n,或者n拆分成不超过n-1的数,f(n,n)=f(n,n-1)+1
- 当n>k,拆分中至少包含一个k,或者拆分中不包含k,f(n,k)=f(n-k,k)+f(n,k-1)
#include<bits/stdc++.h>
using namespace stdn,k;
#define MAXN 500
int dp[MAXN][MAXN];
//动态规划算法
void Split(int n, int k)
{
for(int i=1; i<=n; i++)
for(int j=1; j<=k; j++)
{
if(i==1||j==1)
dp[i][j]=1;
else if(i<j)
dp[i][j]=dp[i][i];
else if(i==j)
dp[i][j]=dp[i][j-1]+1;
else
dp[i][j]=dp[i][j-1]+dp[i-j][j];
//printf("(%d,%d)=%d
", i, j, dp[i][j]);
}
}
int main()
{
int n=5, k=5;
memset(dp, 0, sizeof(dp));
Split(n, k);
printf("(%d,%d)=%d
", n, k, dp[n][k]);
return 0;
}
递归法/备忘录方法
备忘录方法是动态规划(自底向上)的变形,是一种自顶向下的递归方法,但当某个字问题的解求出后将结果保存在一张表(dp)中,而且相同的子问题只计算一次。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500
int dp[MAXN][MAXN];
//递归法
int dpf(int n, int k)
{
if(dp[n][k]!=0)
return dp[n][k];
else if(n==1||k==1)
dp[n][k]=1;
else if(n<k)
dp[n][k]=dpf(n, n);
else if(n==k)
dp[n][k]=dpf(n, n-1)+1;
else
dp[n][k]=dpf(n, k-1)+dpf(n-k, k);
return dp[n][k];
}
int main()
{
int n=5, k=5;
memset(dp, 0, sizeof(dp));
printf("(%d,%d)=%d
", n, k, dpf(n, k));
return 0;
}
下一篇:
【小航的算法日记】最小公倍数
