递归→P1145-数的划分

【问题描述】

  将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。

  例如:n=7,k=3,下面三种分法被认为是相同的。

   1,1,5; 1,5,1; 5,1,1;

  问有多少种不同的分法。

【输入格式】

  两个整数:n,k。

【输出格式】

  一个整数,表示方案数

【输入样例】

7 3

【输出样例】

4

【数据范围】

  6 < n <= 200,2 <= k <= 6
  


【分析】
本题一种思路可以参考P1144整数划分
定义递归函数run(t,k,s)
→t为第几个加数,k为上一个加数,s为当前和
加数分别为a1,a2…ak
因为1,1,5; 1,5,1; 5,1,1视作同一种因此可以仿照整数划分搜索时
底层条件就是当s==n且t==k+1时cnt++

void f(int t,int p,int s)
{

    if(s==n)
    {
        if(t==k+1)//此处t+1是因为第t次最后一个数搜索完后会进入t+1次,若在t==k时就判断,则a[t]没有录入数据
        {
        cnt++;return;
        }
        else return;
    }
    for(int i=p;i<=n-s;i++)
    {
     a[t]=i;
     f(t+1,a[t],s+a[t]);
    }

不过经实际检验,因为6 < n <= 200,2 <= k <= 6
当数据稍微一大就会严重超时,干瞪着眼等着程序跑,所以进行一定程度的优化:

1.对于上面的算法,实则有很多种情况都是不必要的
例如1,1,1;1,1,2…..1,1,4只有1,1,5才是符合的
所以对于第t个数,我们可以直接令其为n-s
接着还要判断 if(n-s>=p)
最后成立才cnt++
2. 这道题与p1144不同的是,只需输出方案数,而不必输出每一种方案的情况,所以不必用定义数组保存(定义的话也无所谓)

这样一来,时间大大缩小,毕竟剪掉一大半不必搜索的路径
核心代码

void f(int t,int p,int s)//t为第几个加数,p为前一个加数,s为当前和 
{

    if(t==k)//分析最后一个加数 
    {
        a[t]=n-s;
        if(a[t]>=a[t-1]) cnt++;
        return;
    }

    for(int i=p;i<=n-s;i++)
     {

      a[t]=i;
      f(t+1,a[t],s+a[t]);
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值