题目描述
将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
{1,1,5};{1,5,1};{5,1,1};
问有多少种不同的分法。 输出一个整数,即不同的分法。
输入格式
两个整数n,k(6<n≤200,2≤k≤6),中间用单个空格隔开。
输出格式
一个整数,即不同的分法。
样例输入
7 3
样例输出
4
#include<iostream>
#include<algorithm>
using namespace std;
int n,k;//数n,分成k份
int stack[7];//存每份分到的数
int sum=0;//计方案数
void dfs(int cnt)
{
if(n==0) return;//n代表的是剩下的数,(当cnt==k时,n==0时,为递归出口)
if(cnt==k){//为了分法不重,我们采用升序进行,(即最后一位数比前一位数大,就可以选择)
if(n>=stack[cnt-1]) sum++;
return;
}
for(int i=stack[cnt-1];i<=n/(k-cnt+1);i++){//对范围进行了一丢丢剪枝操作
//从【前一个数】到【剩下的数的平均数】之间进行选择数进行划分
//因为后一位可以和前一位相等(不下降上升),所以我们从cnt-1开始
//k-cnt+1代表的是我们还需要选的数的个数,n代表的是剩下的数。
//n/(k-cnt+1)代表的是剩下要选的数的平均数
stack[cnt]=i;//第cnt个数划分为i
n=n-i;//剩下的数总数减i
dfs(cnt+1);//下一个数的选择
n=n+i;//回溯
}
}
int main()
{
cin>>n>>k;
stack[0]=1;//从1开始累加或者说选数划分
dfs(1);//从第1个开始选数,选k个
cout<<sum<<endl;
return 0;
}
这里我需要取k个数,并且他们的和为n,主要的是他们的数据没有那么大,那么使用dfs的深搜的话就比较快。
这里取数在考虑不重复的情况下,设定k个数之中,最后一个数最大。
在深搜过程中,n在减小,stack[cnt]在增加,满足条件n>=stack[cnt-1]时,n==4,stack[cnt-1]==3,就可以考虑一个满足条件的k个数了,假如没有这个条件,再一次的dfs(1)会陷入死循环了
不满足上面两个if条件语句的话,进入for语句i=stack[cnt-1],n-=i,此时的n就是剩下的和,再次进入dfs中,一旦满足if语句,就跳出dfs,并且n开始回溯,一直到n=6,此时继续开始for语句i=stack[cnt-1]+1,继续进入dfs循环之中。
总而言之,dfs的深搜原理就是:
void dfs(int x){
判断条件,跳出当前的递归
标记函数或者数组,代表这里已经被检查过了
for循环 {
dfs(x+1)
}
}