1025 数的划分(搜索和递推方法)
难度:普及/提高-
题目类型:递推
提交次数:3
涉及知识:动规
题目描述
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。
输入输出格式
输入格式:
n,k (6<n<=200,2<=k<=6)
输出格式:
一个整数,即不同的分法。
搜索:
代码:
1 #include<iostream> 2 using namespace std; 3 int n, k; 4 int ans; 5 void dfs(int left, int step, int x){ 6 if(step == k-1&&x>0&&x>=left){ 7 ans++; 8 //cout<<x<<endl; 9 } 10 else if(x <= 0||step>=k||x<left) return; 11 else{ 12 for(int i = left; i < n; i++) 13 dfs(i, step+1, x-i); 14 } 15 } 16 int main(){ 17 cin>>n>>k; 18 //for(int i = 0; i < n/k; i++) 19 dfs(1, 0, n); 20 cout<<ans; 21 return 0; 22 }
备注:
感觉想到dfs还是挺自然的,边界条件要想好。为了避免重解,规定从左到右递增,所以代码中标黄部分要注意一下。哎,搜索还得练啊qwq
递推:
1 #include<iostream> 2 using namespace std; 3 int f[205][7]; 4 int main(){ 5 int n, k; 6 int i, j; 7 cin>>n>>k; 8 f[0][0] = 1; 9 for(i = 1; i <= n; i++) 10 for(j = 1; j <= k&&j <= i; j++) 11 f[i][j] = f[i-j][j]+f[i-1][j-1]; 12 cout<<f[n][k]; 13 return 0; 14 }
备注:
参考题解,这个递推方程实在太漂亮!!!必须得记录一下。
下面摘自题解原话,叙述的很清楚。这个思想学组合数学时也曾经用到过。
设F(i,j)为用j个数组成i,答案为F(7,3)的话。
一个思路是,对于F(7,3)=不含1的方案数①+含1的方案数②。
F(i,j)=a(i,j)+b(i,j)
子问题①a(i,j)=F(i-j,j),如其中一个方案2 2 3不含1,则把组成它的j个数都减去1,变成1 1 2的方案,即用3个数组成4.
子问题②b(i,j)=F(i-1,j-1),即用j-1个数组成i-1,则第j个数必为1
对于像 1 1 5,1 5 1,5 1 1这样的方案,从F(7,3)变成了F(5,1),即转化成了用1个数组成5,所以像这样就不会重复。
综上 F(i,j)=F(i-j,i)+F(i-1,j-1).
初始化至少要有F(0,0)=1,其他0。因为对于i==j,即F(x,x)=F(0,x)+F(x-1,x-1). F(0,x)必为0而F(x,x)必为1.
同样,递推的题边界条件都要想好。这里f(0,0)=1就很关键,原因答主也解释的很清楚。