zoukankan      html  css  js  c++  java
  • HOJ (1042) 整数划分

    题目:http://acm.hit.edu.cn/hoj/problem/view?id=1402

    整数划分问题

    Submitted : 886, Accepted : 374

    整数划分是一个经典的问题。希望这道题会对你的组合数学的解题能力有所帮助。

    Input

    每组输入是两个整数n和k。(1 <= n <= 50, 1 <= k <= n)

    Output

    对于每组输入,请输出六行。

    第一行: 将n划分成若干正整数之和的划分数。
    第二行: 将n划分成k个正整数之和的划分数。
    第三行: 将n划分成最大数不超过k的划分数。
    第四行: 将n划分成若干奇正整数之和的划分数。
    第五行: 将n划分成若干不同整数之和的划分数。
    第六行: 打印一个空行。

    Sample Input

    5 2
    Sample Output
    7
    2
    3
    3
    3

    Hint:

    1. 将5划分成若干正整数之和的划分为: 5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
    2. 将5划分成2个正整数之和的划分为: 3+2, 4+1
    3. 将5划分成最大数不超过2的划分为: 1+1+1+1+1, 1+1+1+2, 1+2+2
    4. 将5划分成若干奇正整数之和的划分为: 5, 1+1+3, 1+1+1+1+1
    5. 将5划分成若干不同整数之和的划分为: 5, 1+4, 2+3

    /*

      这是一道非常经典的DP题目,将各种情况综合到一起,对递推思想的理解有很大的帮助啊。

      1.将n划分成不大于m的划分法:

        1).若是划分多个整数可以存在相同的:

         dp[n][m]= dp[n][m-1]+ dp[n-m][m] dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。
         则划分数可以分为两种情况:
             a.划分中每个数都小于 m,相当于每个数不大于 m- 1, 故划分数为 dp[n][m-1].
             b.划分中有一个数为 m. 那就在 n中减去 m ,剩下的就相当于把 n-m 进行划分, 故划分数为 dp[n-m][m];

        2).若是划分多个不同的整数:

        dp[n][m]= dp[n][m-1]+ dp[n-m][m-1] dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。
         同样划分情况分为两种情况:
        a.划分中每个数都小于m,相当于每个数不大于 m-1,划分数为 dp[n][m-1].
        b.划分中有一个数为 m.在n中减去m,剩下相当对n-m进行划分,

         并且每一个数不大于m-1,故划分数为 dp[n-m][m-1]

      2.将n划分成k个数的划分法:

          dp[n][k]= dp[n-k][k]+ dp[n-1][k-1];

        方法可以分为两类:
          第一类: n 份中不包含 1 的分法,为保证每份都 >= 2,可以先拿出 k 个 1 分
        到每一份,然后再把剩下的 n- k 分成 k 份即可,分法有: dp[n-k][k]
           第二类: n 份中至少有一份为 1 的分法,可以先那出一个 1 作为单独的1份,剩
        下的 n- 1 再分成 k- 1 份即可,分法有:dp[n-1][k-1]

      3.将n划分成若干奇数的划分法:

          f[i][j]:将i划分为j个偶数

          g[i][j]:将i划分为j个奇数
         f[i][j] = g[i - j][j];
         g[i][j] = g[i - 1][j - 1] + f[i - j][j];

        方法可以分为两类:

          对于偶数f[i][j]:      i 份中不包含 1 的分法,为保证每份都 >= 2,可以先拿出 j 个 1 分

        到每一份,然后再把剩下的 i - j 分成 j 个奇数即可,分法有: g[i-j][j]

            对于奇数g[i][j]:     i 份中至少有一份为 1 的分法,可以先那出一个 1 作为单独的1份,剩

        下的 n-1 再分成 j- 1 份即g[i - 1][j - 1],还有就是没有一份为 1 的分法可以先拿出 j 个 1 分

        到每一份,然后再把剩下的i - j 分成 j 个偶数即f[i-j][j],分法有:g[i-1][j-1] + f[i-j][j]

        注:第1,2种情况参考了http://www.cnblogs.com/xiaoxian1369/archive/2011/09/12/2174212.html

    */

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn = 52;
    int dp13[maxn][maxn];
    int dp2[maxn][maxn];
    int dp5[maxn][maxn];
    int g[maxn][maxn];//奇数
    int f[maxn][maxn];//偶数
    int n,k;
    void cal(){
        for(int i = 0;i < maxn;i++){
            dp13[i][0] = dp13[0][i] = 0;
            dp2[i][0] = dp2[0][i] = 0;
            dp5[i][0] = dp5[0][i] = 0;
        }
        for(int i = 1;i < maxn;i++){
            for(int j = 1;j < maxn;j++){
                if(i < j){
                    dp13[i][j] = dp13[i][i];
                    dp2[i][j] = 0;
                    dp5[i][j] = dp5[i][i];
                }
                else if(i == j){
                    dp13[i][j] = dp13[i][j-1] + 1;
                    dp2[i][j] = 1;
                    dp5[i][j] = dp5[i][j-1] + 1;
                }
                else{
                    dp13[i][j] = dp13[i-j][j] + dp13[i][j-1];
                    dp2[i][j] = dp2[i-1][j-1] + dp2[i-j][j];
                    dp5[i][j] = dp5[i-j][j-1] + dp5[i][j-1];
                }
            }
        }
        f[0][0] = g[0][0] = 1;
        for(int i = 1;i < maxn;i++){
            for(int j = 1;j <= i;j++){
                f[i][j] = g[i - j][j];
                g[i][j] = g[i-1][j-1]+f[i-j][j];
            }
        }
    }
    int main(){
        cal();
        while(~scanf("%d%d",&n,&k)){
            
            int dp4 = 0;
            for(int i = 0;i <= n;i++)
                dp4 += g[n][i];
            printf("%d\n%d\n%d\n%d\n%d\n\n",dp13[n][n],dp2[n][k],dp13[n][k],dp4,dp5[n][n]);
        }
        return 0;
    }
  • 相关阅读:
    阿里消息队列中间件 RocketMQ 源码分析 —— Message 拉取与消费(上)
    数据库中间件 ShardingJDBC 源码分析 —— SQL 解析(三)之查询SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(六)之删除SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(五)之更新SQL
    消息队列中间件 RocketMQ 源码分析 —— Message 存储
    源码圈 300 胖友的书单整理
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(一)分库分表配置
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(四)之插入SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(二)之分库分表路由
    C#中Math类的用法
  • 原文地址:https://www.cnblogs.com/Roly/p/3078412.html
Copyright © 2011-2022 走看看