首页 > 代码库 > 1025 数的划分(搜索和递推方法)

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就很关键,原因答主也解释的很清楚。

 

1025 数的划分(搜索和递推方法)