将整数 n n n 分成 k k k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如: n = 7 n=7 n=7, k = 3 k=3 k=3,下面三种分法被认为是相同的。
1 , 1 , 5 1,1,5 1,1,5;
1 , 5 , 1 1,5,1 1,5,1;
5 , 1 , 1 5,1,1 5,1,1.
问有多少种不同的分法。
n , k n,k n,k ( 6 < n ≤ 200 6
1 1 1 个整数,即不同的分法。
7 3
4
四种分法为:
1 , 1 , 5 1,1,5 1,1,5;
1 , 2 , 4 1,2,4 1,2,4;
1 , 3 , 3 1,3,3 1,3,3;
2 , 2 , 3 2,2,3 2,2,3.
【题目来源】
NOIP 2001 提高组第二题
for(int j=a[i-1];j<=n/(k-i+1);j++)
{
a[i]=j;
sumt+=j;
dfs(i+1);
sumt-=j;
}
在这里用到了两处剪枝,第一处是根据题目判断出来的可以求分解出来的都是递增的,于是有了j=a[i-1],保证递增性,n/(k-i+1)进行上下界剪枝(目前分出来的数不大于平均数)
if(i==k)
{
if((n-sumt)>=a[i-1])
{
ans++;
}
return;
}
进行边界的判定,同时进行剪枝,与如下对比:
if(i>k)
{
if(sumt==n)
{
ans++;
}
return;
}
对比得少递归了一层(不然洛谷有两个点是超时的)
#include
using namespace std;
int n,k,a[500],ans,sumt;
void dfs(int i)
{
if(i==k)
{
if((n-sumt)>=a[i-1])
{
ans++;
}
return;
}
for(int j=a[i-1];j<=n/(k-i+1);j++)
{
a[i]=j;
sumt+=j;
dfs(i+1);
sumt-=j;
}
}
int main()
{
cin>>n>>k;
a[0]=1;
dfs(1);
cout<<ans;
return 0;
}