zoukankan      html  css  js  c++  java
  • 关于poj 放苹果

    今天重新看整数划分想到了poj1664,写一下解题报告,免得总忘。

    归结为各种分配问题:

    M个苹果放入N个盘子里

    【1】M相同,N相同,可为空:
    允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
    【其实这跟将一个整数m分成n个整数之和是类似的】:
    贴上自己当时的代码:
    View Code
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    using namespace std;

    int f (int m, int n){
    if (m<0)
    return 0;
    if (n==1||m==0)
    return 1;
    return f(m-n,n)+f(m,n-1);
    }

    int main (){
    int t, m, n;
    cin>>t;
    while(t--){
    cin>>m>>n;
    cout<<f(m,n)<<endl;
    }
    return 0;
    }

    f(m-n,n):每个盘子都有苹果
    f(m,n-1):至少有一个盘子没有苹果
    或者用数组实现递归也可以:
    f[m][n] = f[m-n][n]+f[m][n-1],其中f[][1],f[][0],f[1][],f[0][] 都为1。
    即:f[m][n] = f[m][n - 1] + f[m - n][n];   
             = 1 // m== 0 || n == 1      
           = 0 // m < 0
     
    接下来附上一篇转载加少数增减的文章。
    sigma B(n,i) i=1..r
    【2】M相同,N相同,不可为空:
    可以先把每个都放一个苹果,这样问题就转化为:m-n个苹果放进n个盘子里,盘子允许空,即问题【1】
     
    【3】M相同,N不同,可为空:

    盘子是不一样的,相当于m+n个位置放n个盘子,而且最后一个位置必须是盘子。这样,每个盘子之前有几个空位,就是有几个苹果,于是=  C( m+n-1 , n-1 )

    【4】M相同,N不同,不可为空:
    在问题【3】中之所以转换为m+n是因为,m可能大于n,这里不可为空,自然m≥n了,可采用隔板法,在相同的m之间去隔板,而且最后一个苹果后放置一块板子,并且第一个苹果前不能放置板子,即在m-1个空隙中设置n-1个隔板,所以为C( m-1 , n-1 )
    【5】M不同,N相同,可为空:
      sigma S(n,i) i=1..r
    【6】M不同,N相同,不可为空:
      S(n,r)
    【7】M相同,N不同,可为空:
    共N^M种。每个苹果都有N中不同的选择,共M个苹果
    【8】M相同,N不同,不可为空:

      r!*S(n,r)

    问题1:

    m----->相同, n---> 相同,可为空

    将m个苹果放进n个盘子中,盘子允许空,有多少种方法。同时注意例如1、2和2、1这两种方案是一种方案。

    思路:

    其实这跟将一个整数m分成n个整数之和是类似的,

    设f[m][n]为将m分成最多n份的方案数,且其中的方案不重复,每个方案前一个份的值一定不会比后面的大。

    则有:f[m][n] = f[m][n - 1] + f[m - n][n];   
             = 1 // m== 0 || n == 1      
           = 0 // m < 0

    f[m][n - 1]相当于第一盘子中为0,只用将数分成n - 1份即可。
    因为0不会大于任何数,相当于f[m][n - 1]中的方案前面加一个为0的盘子,
    而且不违背f的定义。所以f[m][n - 1]一定是f[m][n]的方案的一部分,即含有0的方案数。
    f[m - n][n]相当于在每个盘子中加一个数1。因为每个盘子中加一个数1不会影响f[m][n - 1]中的方案的可行性,也不会影响f的定义。
    所以f[m - n][n]一定是f[m][n]的方案的一部分,即不含有0的方案数。

    问题2:

    问题描述:将整数N分成K个整数的和 且每个数大于等于A   
    小于等于B 求有多少种分法

    1. int Dynamics(int n, int k, int min) //将n分为k个整数 最小的大于等于min,最大不超过B   
    2. {  
    3.   
    4.     if(n < min) return 0;//当剩下的 比min小,则不符合要求 返回0   
    5.     if(k == 1) return 1;    
    6.     int sum = 0;  
    7.     for(int t = min; t <= B; t++)  
    8.     {  
    9.      sum += Dynamics(n-t, k-1, t);  
    10.     }  
    11.     return  sum;  
    12.   
    13. }  

    问题3:

    m----->相同, n---> 相同,不能为空

    将m个苹果放进n个盘子中,有多少种方法。同时注意例如1、2和2、1这两种方案是一种方案。

    思路:

    先把每个都放一个苹果,这样问题就转化为:m-n个苹果放进n个盘子里,盘子允许空,即问题1

    问题4:

    第一类Stirling数是有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目

    递推公式为,
    S(n,0) = 0, S(1,1) = 1.
    S(n,k) = S(n-1,k-1) + (n-1)S(n-1,k)。

    n个元素的集合分作k个环排列的方法是s(n,k),那么

    1.可由前n-1个元素k-1个环的s(n-1,k-1); 即最后一个元素为单环,前n-1个构成k-1环;

    2.第n个元素一定不是单环,可以由n-1个元素k个环,把第n个数任意的放入一个环中组成新环!即得到n个

    元素的集合分作k个环,假设n个元素的集合分作k个环,那么由于n,不在单环中,那么可以把n所在的环中把n

    剔除,即得到了n-1个元素,k个环,即充分与必要性都得证!

    因而:S(n,k) = S(n-1,k-1) + (n-1)S(n-1,k)。得证!

    问题5:

    第二类Stirling数是把包含n个元素的集合划分为正好k个非空子集的方法的数目。
    //n->有区别,K->非空,没区别
    递推公式为,
    S(n,n) = S(n,1) = 1,
    S(n,k) = S(n-1,k-1) + kS(n-1,k).


    上面的递推式可以用组合证明:
    一方面,如果将第n个元素单独拿出来划分成1个集合,那么方法数是S(n-1,k-1);
    另一方面,如果第n个元素所在的集合不止一个元素,那么可以先将剩下的n-1个元素划分好了以后再选一个集合把第n个元素放进去,方法数是k*S(n-1,k);
    有加法原理得证

    问题6:

    Bell数和Stirling数

    B(n)是包含n个元素的集合的划分方法的数目。

    集合的划分:非空,

    B(0) = 1, B(1) = 1,

    B(n) = Sum(1,n) S(n,k).  其中Sum(1,n)表示对k从1到n求和,

    问题7:

    当K是有区别的时候,则一般都要在没有区别的基础上乘以K的全排列。

     
     
  • 相关阅读:
    驱动之类似内存接口的介绍与应用20170209
    驱动之LCD的介绍与应用20170209
    驱动之NandFlash的介绍与应用20170209
    Android广播机制的深入学习
    C++的隐式类型转换与转换操作符
    PackageManager使用
    在命令行中通过adb shell am broadcast发送广播通知
    Android无法收到指定广播的问题总结
    overload, override和overwrite之间的区别
    Longest Substring Without Repeating Characters -- LeetCode
  • 原文地址:https://www.cnblogs.com/celia01/p/2358673.html
Copyright © 2011-2022 走看看