整数划分解报告(背包求解)

1.问题描述:

    给定一个正整数N和K

 

    1.> 将n划分成若干正整数之和的划分数。

    2.> 将n划分成k个正整数之和的划分数。

    3.> 将n划分成最大数不超过k的划分数。

    4.> 将n划分成若干奇正整数之和的划分数。

    5.> 将n划分成若干不同整数之和的划分数。

 

2.问题分类:总的来说这些都是背包问题;

 

第一个问:就是一个完全背包,背包有 1 --- N 种,第 i 种背包的重量为 i ,价值为 i ;这很好解决:

 

        dp[0] = 1;

        for (i = 1;i <= N;i++)

            for (j = i;j <= N;j++)

                dp[j] += dp[j-i];

其中 dp[j] 是用前 i 个数能构成 j 的种类数,则结果就为 dp[N]

 

看完这个问题了,那么 第3个问就知道了 , 即用前 K 种背包来装 所得结果,只需把第一层循环的 i <= N 改为 i <= K 即可;

 

        dp[0] = 1;

        for (i = 1;i <= K;i++)

            for (j = i;j <= N;j++)

                dp[j] += dp[j-i];   结果同样为 dp[N] ;

 

那么第四个问呢,想想是奇数,那么 i = 2,4,6,…… 等等值就不能取了,因为这些背包种类不合要求,这很简单啊  i++ 改为 i += 2 不就行了;

 

        dp[0] = 1;

        for (i = 1;i <= N;i+=2)

            for (j = i;j <= N;j++)

                dp[j] += dp[j-i];   结果同样为 dp[N] ;

 

再看看第五个问,若干个不同的???想到了什么,就是一种背包最多只能用一次???这是什么,经典的 01背包 啊,与第一个问的不同就是第二层循环的顺序而已;

 

        dp[0] = 1;

        for (i = 1;i <= N;i++)

            for (j = n;j >= i ;j--)

                dp[j] += dp[j-i];

 

最后我们来思考第二个问:(这题在nyoj176上可以练习)

         

 将n 分成k个正整数之和的种类数,等同于把 m 个苹果放在 n 个盘子里,每个盘子不空。

   易知当n=1,k=1,放法为1。当n==k时,放法为1,

   当k==1时,放法为1。

   若n<k, 这样必有盘子是空的,此时放法为0.

分为两种情况:1.至少有一个盘子中放了一个苹果;  2.每个盘子中苹果个数都大于1个。

好了,至此,递归方法出来了:  

 

#include <cstdio>
#include <iostream>

using namespace std;

int fun(int m, int n)  //等同于把 m 个苹果放在 n 个盘子里,每个盘子不空
{
    if(m < n)
        return 0;
    if(m == n || n == 1)
        return 1;
    else
        return fun(m-n, n) + fun(m-1, n-1);//分成两种情况:1.至少有一个盘子中放了一个苹果;  2.每个盘子中苹果个数都大于1个
}

int main()
{
    int T, n, m;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &m, &n);
        printf("%d\n", fun(m, n));
    }
    return 0;
}


//本题更快的方法就是先打表
 
#include<stdio.h>
int main()
{
    int a,b,n,m,k;
    int ok[105][105]={0};
    ok[1][1]=1;
    for(a=2;a<=100;a++)
    {
        for(b=1;b<=a;b++)
            ok[a][b]=ok[a-b][b]+ok[a-1][b-1];
    }
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d%d",&n,&m);
        printf("%d\n",ok[n][m]);
    }
}

--------------------------------

这都是基础的背包问题!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值