目录
题目描述
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5;
1,5,1;
5,1,1.
问有多少种不同的分法。
输入输出格式
输入格式:
n,k (6<n≤200,2≤k≤6)
输出格式:
1个整数,即不同的分法。
输入输出样例
输入样例#1: 复制
7 3
输出样例#1: 复制
4
说明
四种分法为:
1,1,5
1,2,4;
1,3,3;
2,2,3.
DP
f[ i ][ x ] 表示 i 分成 x 个非空的数的方案数,
当 i < x 时,f[ i ][ x ]=0,当 i==x 时,f[ i ][ x ]=1
当 x 为1的时候,就是只用分一份的时候 f 的值就是1
关键是要知道如下情况:
- 有1的情况,就是确定了有一段的长度为1,此时方案数:
- 此时就相当于有一个抽屉已经确定了并且那个抽屉里就是1,所以这个时候分法就等于把剩下的 i-1 个数分在剩下的 x-1段(抽屉苹果都被占了一个)的分法
- 第二种情况是,不含1,此时方案数: 此时i必须要大于x
- 没1的时候和挡板法的情况类似,因为没有一个抽屉是1,所以可以往每个抽屉里的都先放上一个1,总方法数就相当于把剩下的数(i-x)分到x个抽屉里,所以就得到了这样的状态转移方程。
状态转移方程:
代码:
#include<iostream>
using namespace std;
int n,k;
int f[210][7];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++) f[i][1]=1;
for(int i=1;i<=n;i++)
for(int x=2;x<=k;x++)//x从2开始
{
if(i>x) f[i][x]=f[i-1][x-1]+f[i-x][x];
else f[i][x]=f[i-1][x-1];
}
cout<<f[n][k];
return 0;
}
DFS
就注意一个点:如果不剪枝,不单单是TLE的问题,连正确答案都出不来,会重复计算
代码:
#include<iostream>
using namespace std;
int n,k;
int sum;
void dfs(int step,int num,int rest)
{
if(rest==1)//当只剩下一段待分了,可以认为已经分完
{ sum++;return;}
/* 同时循环最大只能进行到t/s,
避免出现因前面的数过大而导致后面的数无法取的情况。*/
//for(int i=step;i<=num;i++)
//剪枝:不需要枚举到num,否则既有可能重复计算,又会加大运算
for(int i=step;i<=num/rest;i++) //剪枝 i<=num/rest
dfs(i,num-i,rest-1);
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
dfs(1,n,k);
cout<<sum<<endl;
return 0;
}