题目链接:P1025 数的划分
用k个数组成n,且不考虑数的顺序。
首先我们考虑用搜索的做法,因为数的顺序无关,所以我们采用从小到大的搜索方式,注意有个剪枝
void dfs(int pre,int step,int sum)
{
if (step == k)
{
if (sum == n) ans++;
return;
}
for (int i = pre; sum + i*(k - step) <= n; i++)
dfs(i, step + 1, sum + i);
}
这里一定要加sum + i*(k - step) <= n这个剪枝,这句话什么意思呢,就是当前已经确定了step个数了,还剩下k-step个数,sum是当前step个数的和,如果剩下(k-step)都是i的话都不满足总和小于n的话就退出,因为接下来搜索的数必定是大于等于i的,如果剩下(k-step)都是i的话都不满足,那么接下来的搜索也一定不满足,因此退出
接下来考虑dp的做法,我们
设F(i,j)为用j个数组成i,答案即为F(7,3)的。
一个思路是,对于F(7,3)=不含1的方案数+含1的方案数
首先含1的方案数很好处理,就是前我们用j-1个数去组成i-1,剩下一个数就是1,因此这个方案数等于F(i-1,j-1).
那么不含1的数的方案呢,不含1的方案说明我们选的方案的j个数每个数都大于1,那我们就让这j个数每个数都减去1,最后这j个数的和是i-j,因此这个方案数就是F(i-j,j),
这里有些问题,那我们为什么让这j个数每个都减去1呢?为什么不减去2,3,4...呢?因为这个方案是不含1的,选的数是大于等于1的,但不一定大于等于2,3,4...,所以减去1.
还有疑问,为什么必须选择j个数每个都减去1,而不选择j-1,j-2,或者j-x个数呢,让它们每个都减1。
如果选择j-x个数那么问题来了,我们到底选择这j个数里的哪j-x个数呢,换句话说,到底哪x个数不减1呢。所以这种去掉x个数的方案不唯一,有多种情况,只有这j个数,每个都去掉1,这是唯一的情况,我们直接加上F(i-j,j)即可,当然这是在i-j>=j的时候。
所以我们得到了
F(i,j)=F(i-1,j-1)+F(i-j,j)
#include<bits/stdc++.h> using namespace std; int n, k; int f[205][10]; int main() { cin >> n >> k; for (int i = 0; i <= n; i++) { f[i][1] = 1; f[i][i] = 1; } for (int i = 2; i <= n; i++) { for (int j = 1; j <= k; j++) { f[i][j] = f[i - 1][j - 1]; if (i - j >= j) f[i][j] += f[i - j][j]; } } cout << f[n][k] << endl; return 0; }