计蒜客 - T2155 -- 数的划分【记忆化搜索 or dp or 搜索】

数的划分
Description

将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。

Input

有多则测试数据。
对于每组测试数据,仅有一行,包括两个整数n,k (6<n<=200,2<=k<=6)。

Output

对于每组测试数据,输出一个整数,即不同的分法。

Sample Input

7 3

Sample Output

4

Hint

输入: 7 3
输出:4 {四种分法为:1,1,5; 1,2,4; 1,3,3; 2,2,3;}

思路(dp)

它的划分时候子划分而来的,比如说7,4他是由6,4划分而来的。
搜索状态转移,考虑两种情况,
1.划分包含1的情况dp(n-1, k - 1); 就相当于把1单独拿出来
2.划分不包含1的情况dp(n-k, k); 相当于将n-m分成m个数,每个数至少大于1.
我们知道dp(i, 1) 和dp(i,i)是肯定为1的,因为任何一个数的1个划分是它本身,k个数的k个划分也只有一种情况

AC代码
/**
	dp O(n * m)
**/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 205;
int dp[maxn][maxn];
void solve(){
	int n, k;
	scanf("%d%d", &n, &k);
	memset(dp, 0, sizeof(dp));
	//每个数化分成1个只有一种 
	for (int i = 1; i <= n;++i)	dp[i][1] = 1;
	for (int i = 2; i <= n; ++i){
		for (int j = 2; j <= k && j <= i; ++j){
			dp[i][j] = dp[i - 1][j - 1] + dp[i - j][j];
		}
	}
	printf("%d\n", dp[n][k]);
} 
int main(){
	solve();
	return 0;
}
思路(搜索)

和dp是一个道理,但是是递归实现的,重复算了很多数据

AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int dfs(int n, int k){
	if (k == 1 || n == k)	return 1;
	if (k <= 0 || n <= 0 || n < k)	return 0;
	return dfs(n - 1, k - 1) + dfs(n - k, k);
}
void solve(){
	int n, k;
	scanf("%d%d", &n, &k);
	int ans = dfs(n, k);
	printf("%d\n", ans);
} 
int main(){
	solve();
	return 0;
}
思路(记忆化搜索)

搜索过的状态记录下来,下一次搜索到了就直接加上即可。

AC代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 205;
int dp[maxn][maxn];
int dfs(int n, int k){
	if (dp[n][k] >= 0)	return dp[n][k];
	dp[n][k] = 0;
	if (n - 1 > 0 && k - 1 > 0){
		dp[n][k] += dfs(n -1, k - 1);
	}
	if (n - k > 0 && k > 0){
		dp[n][k] += dfs(n - k, k);
	}
	return dp[n][k];
}
void solve(){
	int n, k;
	scanf("%d%d", &n, &k);
	memset(dp, -1, sizeof(dp));
	//每个数化分成1个只有一种 
	for (int i = 1; i <= n;++i)	dp[i][1] = 1;
	int ans = dfs(n, k);
	printf("%d\n", ans);
} 
int main(){
	solve();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空皓月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值