整数拆分,dp入门经典

整数拆分
给定一个整数n,将其无序拆分成最大数为k的拆分数,(n,k不超出100) 要求:所有的拆分方案不重复。 如当n=4,k=4时,一共有5种拆分方案,拆分如下:
(1)4=1+1+1+1
(2)4=1+1+2
(3)4=1+3
(4)4=2+2
(5)4=4

输入格式:

每一行输入一组整数n,k,遇到键盘结束符^Z或文件结束符EOF时结束输入。

输出格式:

按行输出每组的拆分方案数。

输入样例:

4,4
5,4

输出样例:

5
6

解题思路:

题意:就是给你两个正整数n,k。然后把n拆分成若干个整数,且每个整数的最大值不能大于k。而且拆分完的序列是无序的。比如:1 1 2和2 1 1是算同一种方案。题目要你计算方案数有多少中。

1. 暴力解法

既让要拆分成若干个整数和,那么最容易想到的就是,我把数一开始都拆分成n个1相加,然后减少1的个数。比如输入4,4时,一开始拆分成1,1,1,1,然后还可以拆分成1,1,2。接下去以此类推,每次用较小的数合成一个较大的数。但很显然,这样的做法复杂度是很大的。以下是暴力解法的代码。

#include<stdio.h>
int n,cnt;
void DFS(int sum, int temp, int k)
{
	if (sum == n)
		cnt++;
	if (sum < n && temp <= k)
		DFS(sum + temp, temp, k);
	if (sum != n && temp <= k)
		DFS(sum, temp + 1, k);
	else if (temp > k)
		return;
}

int main()
{
    int k;
	while (~scanf("%d,%d", &n, &k))
	{
		cnt = 0;
		DFS(0, 1, k);
		printf("%d\n", cnt);
	}
	return 0;
}

但是这么只能过第一个测试点,其他的地方都超时了。

在这里插入图片描述

2. 动态规划

既然暴力的方法行不通,那么我们就该换种思路了。实在没有思路的时候我们可以尝试手动计算出n,k都较小时的拆分方案数。结果我们不难发现以下几条规律。

  1. 当n==1时,无论k为何值,都只有一种拆分方案。即{1}。

  2. 当k==1时,无论n为何值,都只有一种拆分方案。即{1,1,……,1,1}。因为拆分的最大数不能超过k,所以只能拆成1。

  3. 当n==k时,根据拆分出来的数是否包含n,可以分成两种情况。

    • 拆分出来的整数包含n,那就只有一种情况,即{n}。
    • 拆分出来的整数不包含n,那么这些拆分出来的数中,一定比n小,即n的所有(n-1)拆分。因此dp[n][k]=1+dp[n][k-1];
  4. 当n<k时,因为拆分出来的最大数永远不可能达到k。所以等价于n的所有n拆分。因此dp[n][k]=dp[n][n];

  5. 当n>k时,根据拆分出来的整数中是否包含k,可以分为两种情况:

    • 拆分出来的整数中包含k,即{k,{a1,a2,……,ai}),其中{a1,a2,……,ai}的和为n-k,可能再次出现k,因此是(n-k)的k拆分。因此这种情况的拆分数是dp[n-k][k]。
    • 拆分出来的整数中不包含k的情况,则拆分出来的整数中所有值都比k小,即n的(k-1)划分。拆分数为dp[n][k-1]。

    所以dp[n][k]=dp[n-k][k]+dp[n][k-1]。

以下是dp写法的参考代码。

#include<bits/stdc++.h>
using namespace std;
int main() {
	int n, k;
	while (~scanf("%d,%d", &n, &k)) {
		int dp[200][200];
		int i, j;
		for (i = 1; i <= n; i++) {
			for (j = 1; j <= k; j++) {
				if (j == 1 || i == 1)
					dp[i][j] = 1;
				else if (j == i) {
					dp[i][j] = dp[i][j - 1] + 1;
				}
				else if (i < j) {
					dp[i][j] = dp[i][i];
				}
				else if (i > j) {
					dp[i][j] = dp[i][j - 1] + dp[i - j][j];
				}
			}
		}
		printf("%d\n", dp[n][k]);
	}
	return 0;
}

在这里插入图片描述

发布了50 篇原创文章 · 获赞 52 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43058685/article/details/103228145
今日推荐