您的位置:首页 > 其它

【动态规划】划分整数

2018-03-28 20:00 274 查看


大致思路(关键):
dp[i][j] 代表能把i划分成不多于j个正整数相加。

当i<j:显然最多只能划分成i个1相加,或者划分成小于i个份数,即划分成小于等于i份。所以=dp[i][i]

当i>j:
①如果要刚好分为j份正整数,则=dp[i-j][j] 。 (这步比较难想,但是我通过”逆向思考“和“坐位子思路”想懂了:
先看dp[i-j][j]嘛,可以把i-j这个数分为j或少于j个正整数相加,想象有j个位子,当分为少于j个正整数相加时(比如说j-2个正整数相加),我们可以把那剩下的两个位子以0占位。那么你想想,对每一种情况,现在把j个位子上每个数都+1(使i-j->i),是不是就保证了每个位子上都是正整数。这样就符合了dp[i][j]让它j个位子上都是正整数,从而满足了刚好把i分为j份正整数相加。

②如果要分为少于j份正整数相加,那么就是要<j即<=j-1,所以这不就是dp[i][j-1]吗?(抓住j的含义——小于等于j份
所以=dp[i-j][j]+dp[i][j-1]

当i==j:
很明显你要把i分为j份或者小于j份:分成j份那就是分成j个1即i个1,分成<j份那就分成<=j-1份。所以=1+dp[i][j-1]

临界条件:dp[1][1]=1;

AC代码:#include<iostream>
#include<bits/stdc++.h>
using namespace std;

long long dp[301][301]; //dp
[k]表示把n分解成不多于k个正整数相加
int main()
{
memset(dp,0,sizeof(dp));
int n,k;
cin>>n>>k;
dp[1][1]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
if(i==1 && j==1 )
continue;
if(i==j)
{
dp[i][j]=1+dp[i][j-1];
}
if(i>j)
{
dp[i][j]=dp[i-j][j]+dp[i][j-1];
}
if(i<j)
{
dp[i][j]=dp[i][i];
}
}
}
cout<<dp
[k];
return 0;
} 感觉思考动态规划其实不要太陷入数字里去,而是在把dp数组的下标和其值代表的含义记清楚之后,去联系实际递推各种情况之间的联系。也就是重要在找状态转移方程上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: