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

 

posted @ 2016-10-06 19:06  timeaftertime  阅读(611)  评论(0编辑  收藏  举报