zoukankan      html  css  js  c++  java
  • 组合数学及其应用——计数问题

     问题一:将一个2003边形的每个顶点染成红、蓝、绿三种颜色之一,使得相邻顶点的颜色互不相同,请问有多少种满足条件的方法?

      分析:直接求解似乎不太现实,将多边形的边数看成变量,我们设置T(n)记录方案数,应用简单的组合计数原理,容易看到T(3) = 6 , T(4) = 18。基于这么有限的条件,我们如何求解T(2003)呢?递推似乎是解决这种问题的好方法。

      我们考虑基于T(n-1),在第n-1后面再加一个点形成n边形。

      如果第1个点和第n-1个点同色,对于第n个顶点我们有2种选择,而对于剩余n-1个顶点,我们基于n-2个顶点的方案数,每次添加一个和第一个顶点相同颜色的点,便完成了所有情况的构造,此时即得到2T(n-2)种方案。

      如果第1个点和第n-1个点异色,那么对于第n个顶点我们只有一种方案,便基于T(n-1)的基础上添加一个点即可,我们得到T(n-1)种方案。

      由此我们可以得到结论:T(n) = T(n-1) + 2T(n-2),结合初始条件,T(2003)显然是可求的。

      如果说我们有台计算机,那么基于上面的条件其实也就可以求解了,但如果没有的话,我们则需要进一步从这个递推式中挖掘信息。

      外延一种根据递推式求解通项的方法:对于递推式a(n+2) = pa(n+1) + qa(n),a1 = α,a2 = β,x^2 + px + q = 0是其特征方程的根,x1、x2为特征方程的解。当x1 != x2,an = Ax1^(n-1) + Bx2^(n-1) ;而当x1 = x2 , an = (A + Bn)x^(n-1)。其中A和B通过初始条件a1、a2的值,利用待定系数的方法求解。

      那么考察此题给出递推等式,我们可得出an的通项,T(2003)也不难求解了。

      问题二:设n是正整数。若由n个正整数组成的数列(可以相同)满足:对于每个正整数k(k >= 2),当k在此数列中时,k - 1也在此数列中,且k-1第一次出现的位置在k最后一次出现的位置的前面,则称该数列为“满的”。问:对于每个整数n,有多少个满的数列?

      分析:由题目鉴定,我们可知对于r = max{a1,a2……an},则区间[1,r-1]的整数都在该数列当中,我们设置集合Si来表示数列中第k个元素ak = i的下标k,即Si = {k | ak = i},之所以定义这个集合,是为了方便利用题设条件,由此我们可知min Si-1 < max Si , 则此时我们可以对Si所含元素进行一个简单的排序。

      S1 = {b1,b2,……b(k1)}    (b1 > b2……>b(k1) 且 b(k1) > b(k1 + 1))

      S2 = {b(k1+1) , b(k1 + 2)……b(k2)}  (b(k1+1) > b(k1+2)……>b(k2)且b(k2) > b(k2 + 1))

      ……

      由此我们考察S1、S2……Sr不难发现,r个集合的n个元素与{1,2,3……n}满足一个双射关系,那么基于这种双射关系,我们通过{1,2,3……n}形成n!种排列,然后相应的去匹配ak对应的正整数,便可构造出满的数列,由此不难得出该题的结论,对于每个n,有n!个满的数列。

      问题三:桌子上有六个空钱包,将12枚2元硬币放入这些钱包中,至多剩余一个钱包,问有多少种方法?

      分析:这算是组合计数问题里面比较基础的问题了。题设所说至多剩余一个,即分为没有空钱包和剩余一个空钱包,我们只需要分情况讨论然后将两种情况的结果相加即可。

      ①没有空钱包,这种情况对应着将6个硬币放入6个钱包(允许有空钱包)的情况,因此在给6个钱包分组的时候,会形成11个位置,分成6组需要选择5个位置,即C(11,5)。

      ②如果有一个空钱包,首先要选出这个空钱包,即C(6,1),将12个硬币放入5个钱包,对应着将7个硬币放入5个钱包(允许有空钱包)的情况,采取①的思路,我们得到C(13,4)。

      综合起来,这道题的解即为C(11,5) + 6C(13,4)。

      问题四:设六边形ABCDEF是边长为1的正六边形,O是六边形的中心,除了六边形的每一条边,可以从O到每个顶点连一条线段,共得到12条长度为1的线段,一条路径是指从O出发,沿着线段最后又回到O,问:长度为2003的路径共有多少条?

      分析:首先我们应该考虑的是求解这道问题的通式,我们设置a[n]记录长度为n的路径,而b[n]表示从某个顶点出发,到达O的路径的长度。考察该几何图形,我们容易看到如下的递推关系式。

      a[n] = 6b[n-1] (考察a[n]路径,去掉其最后一步,得到此递推式)

      b[n] = a[n-1] + 2b[n-1](考察b[n]路径,去掉其最后一步,得到递推式)

      由此我们不难得出关于a[n]的递推式——a[n+2] - 2a[n+1] - 6a[n] = 0。同样,如果这是一道编程问题,我们基于这个递推式就可以求解了,但是如果是个数学题的话,我们则需要给予这个递推式进一步求其通式,其方法在问题一种已经给出。

      此题的关键是寻求这种递推关系,而寻求递推关系的关键则是基于一种状态,通过去掉最后一个步来建立起与前一种状态的联系,而所谓的”去掉最后一步“是否完成的足够全面(没有重复没有漏),则是递推关系是否正确的关键一环。

      问题五:将n(n>=1)个有标记的球分别分配给九个人A、B、C、D、E、F、G、H、I,问:有多少种分配方法,使得A得到的球的数目与B、C、D、E一共得到的球的数目相同?

      分析:此题是非常考验数学观察力和构造能力的,既然是9个人,A球和另外四个球数量相同,我们考察(x^2 + x + x + x + x + 1 + 1 + 1 + 1)^n这样一个式子。我们规定如果将第k个球给A,那么选取第k个因子中的x^2;如果将第k个球分给B、C、D、E,则选取第k个因子当中的第1、2、3、4个1;如果将第k个球给F、G、H、I,则选取第k个因子中第1、2、3、4个x,我们会看到,为了满足A的球和B、C、D、E的球数和相同,需要选择一个因子的x^2,就要对应选择另一个因子中的某个1,而其余因子只能选择x,由此不难看出,(x^2+4x +4)^n展开式中x^n的系数变式方案的总数。利用牛顿二项式定理,对于(x+2)^2n,x^n的系数为2^nC(2n,n)。

      这道题目呈现出来的方法思想,对于学过生成函数算法的读者来说可能比较熟悉。即一种将组合计数和函数表达式联系在一起,通过证明函数与组合计数的等效转化性,然后基于函数进行运算。

      问题六:对所有是数字1~7的全排列的七位数,从小到大进行排序。问:数字3654217出现在第几个?

      这也是一道比较基础的组合计数问题,我们考虑第一个数字是1、2的情况,得到2*6!个数字;第一个数字是3第二位数字是1、2、4、5,得到4*5!个数字;类似地依次分析接下来的每一位,即,共有2*6! + 4*5! + 3*4! + 2*3! + 1*2! ,在此结果上+1便得到最终结果。

      问题七:数916238457是一个包含1~9每个数字恰好一次的九位数的例子,其还具有性质:数1~5以正常的顺序出现,但1~6不以正常的顺序出现。问:这样的数有多少个?

      题目很简单,关键点在于理解这个9位数的性质,我们先将1~5排好顺序,形成6个空隙,按照性质,数字6有5个符合要求的空隙,即有5种方法,然后再依次填入7、8、9,则答案为5 * 7 * 8 * 9 = 2520.

      问题八:有多少种方法可将2011/2010表示成两个n+1/n(n∈Z)型分数的乘积?(其中,ab和ba认为是一种方法)

      我们设2011/2010 = (p + 1)/p * (q + 1)/q,进行整理可得p = 2010 + (2010*2011)/(q - 2010) , q = 2010 + (2010*2011)/(p-2010)。由因为q、p都是正整数,所以p - 2010是2010*2011的因子即可,因此对其进行素因子分解,有2010*2011 = 2 * 3 * 5 * 67 *2011 , 其因子数共有C(5,1) + C(5,2) + C(5,3) + C(5,4) + C(5,5) = 2^5,由于p、q表示形式上的对称性,当存在一组解(p,q)的时候,另外一组解(q,p)也会满足条件,因此这里共有16种方法。

      问题九:令f(n)为满足4x+3y+2z = 2000 = n的正整数数对(x,y,z)的个数,求f(2009) - f(2000)。

      设4x+3y+2z = 2000 , 观察到2009 - 2000 = 9 , 并且y的系数3是9的因子,因此我们构造x' = x , y' = y + 3 ,z' = z,则有4x' + 3y' + 2z' = 2009,因此我们可以看到在y'的解空间中,y' > 3的时候与y的解空间形成双射,即f(2009) - f(2000)的值为y' = 1 , 2 , 3时可以取的(x,y,z)的整数对的个数。

      y' = 1   =>    4x' + 2z' = 2006    =>  501组。

      y' = 2   =>    4x' + 2z' = 2003    =>  0组。

      y' = 3   =>    4x' + 2z' = 2000    => 499组。

      因此f(2009) - f(2000) = 499  + 501 = 1000.

      问题十:从1°、2°……179°选出三个角度使其成为非等腰三角形的三个内角,问:有多少种选法?

      我们设三个内角分别是x、y、z,由x + y + z = 180 , 我们能够得到C(179,2)组解,需要知道的是这里的解的组合有次序的,即是一种排列。随后我们需要找到等腰三角形的情况,为了好分析,我们先把等边三角形单独拿出来分析。x、y、z用(x,y,z)来表示。

      (60,60,60) , 1组。

      (1,1,178) 、(2,2,176)……(89、89、2) , 由于我们求总情况数的时候是一种排列,这里当然需要保持一致,共88C(3,1)组。

      求解最终的答案不要忘了去除排列性,即答案为C(179,2) - 1 - 88C(3,1) / A(3,3)。

      问题十一:求满足下述条件的正整数的数目,可以被9整除,位数不超过2008,且各位数字中至少有两位数字是9.

      总数:利用基本的分步乘法原理,有10^2008 - 1种。(减掉0的情况)

      其中9的倍数有(10^2008 - 1)/9种。

      现在考虑这些数字各位数字中至多有1个9的情况的数量,然后用总数减掉便可得答案。

      (1)有0位9,我们对前2007位在0~8中随机选择,为使这个2008位的整数被9整除,第2008位的数字是唯一确定的,因此这种情况下得到9^2007 - 1种情况.

      (2)有1位9,类似上面的过程,在这里我们得到C(2008,1)9^2006种情况。(显然这种情况下是不会出现0的)

      因此最终满足题意的数目共有(10^2008  - 1)/9 - (9^2007 - 1) - 2008*9^2006。

      问题十二:有六个红球、三个篮球、三个黄球。将这些球放在一条直线上,假设同色的球没有区别。试问:有多少种不同的方法,使得同色的球不相邻?

      这其实是组合计数问题中的一类“不相邻”问题,我们应该先将数量较多的球摆好,然后将颜色不同的球插入到其中。在这个问题中,我们首先将6个红球摆好——10101010101(1代表红球,0代表必须填充的间隔),而我们手头还有另外的6个球,因此我们能够知道,蓝色球和黄色球至多相邻一次。那么下面我们便开始分别讨论。

      (1)蓝色球和黄色球不相邻:显然有C(2,1)*C(6,3)种情况。

      (2)蓝色球和黄色球相邻一次:我们将相邻的蓝色球和黄色球合成一个花球,这种合成包括2种方法,则此时出现的情况数为2 * 5! / (2! * 2! )。

      问题十三:15张卡片上分别写着1,2,……15.现从中至少选出一张卡片。问:有多少种选择方式,使得所选的所有卡片上的数均大于或等于被选的卡片的张数?

      我们从更加一般的角度来分析这个问题,如果给出了k张卡片,考虑用递推的思维来建立起前后状态的关系,我们进行如下的分类讨论,记f[k]表示:

      (1)不选第k张卡片,则得到f[k-1]种情况。

      (2)选择了第k张卡片。

        (i)不选其余卡片,1种情况。

        (ii)选择其余卡片,很容易看到,当前情况就不能够选第1张卡片了,对于剩余的2、3……k-1张,我们将其重新编号:1,2……k-2,可以看到,我们在f[k-2]种情况的基础上,加上第k张卡片,由于增加了一张卡片数,应该将每个卡片的编号+1,这其实刚好与我们进行编号前的所有情况是一一对应的,由此我们得到了f[n-2]种情况。

      综合起来,我们发现,f[n] = f[n-1] + f[n-2] + 1,基于这个递推式,我们就很容易进行求解了。

      问题十四:设正整数m、n互素,s是任意一个整数,求集合{1,2,3……m+n-1}的子集A的数目,使得|A| = m,且∑x ≡ s(mod n),其中x∈A.

      我们容易看到,元素个数为m的子集个数为C(m+n-1,m)种,现在我们需要探讨在这些种集合中,(∑x) mod n的结果是否会出现重复,或者说如何进行重复。

      我们基于这样一条数论中结论,如果(p,n) = 1,则n mod p 、2n mod p…… (p-1)n mod p是1、2、……p-1的一个某种次序的排列(证明费马小定理的用到的结论,可用鸽巢原理去证明)。那么现在用到这里,对于某种情况∑xk,我们进行xk <- xk + 1的操作,则∑xk增加了m,那么进行n次这样的操作,结果便是0、1、2……n-1的一个某种次序的排列,那么基于这个结论,我们这个过程放在一个m + n - 1的数环上,对于某个长度为m的集合,旋转n次,∑xk mod n = 1、2、3……n-1,可以看到,所有的情况都会存在与这样一个旋转的系中,因此我们得到结论,∑x ≡ s(mod n),s取0、1、2……n-1的情况数目是相等的,因此该题最终的答案是1/n * C(m+n-1,m).

      问题十五(uva 12034):

      A、B两个人赛马,最终名次有3种可能:并列第一;A第一B第二;A第二B第一。那么按照这种排名方法,给出整数n,求解最终排名的所有情况数。

    分析:考虑基本的递推原理就能够得到这道问题的解,设dp[n]是n个人不同排名的情况数,选择i个人成为并列第1,完成问题规模的削减,然后将各个情况累加起来,可以得到如下的状态转移方程:

     

    #include<cstdio>
    using namespace std;
    
    const int MOD = 10056;
    const int maxn = 1005;
    int dp[maxn];
    int C[maxn][maxn];
    
    void init()
    {
        for(int i = 0;i <  maxn;i++)
        {
             C[i][0] = 1;
             for(int j = 1;j <= i;j++)
                   C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD;
        }
    }
    int main()
    {
         init();
    
    
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 3;
        int n;
        int T;
        int tt = 1;
    
    
        for(int i = 3;i <= maxn;i++)
            {
                 int sum = 0;
            for(int j = 1;j <= i;j++)
                {
                       sum += (C[i][j]*dp[i-j])%MOD;
                       //printf("%d
    ",(C[i][j]*dp[i-j]));
    
                }
                dp[i] = sum%MOD;
            }
    
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
              printf("Case %d: ",tt++);
            if(n == 1  || n == 2)  {printf("%d
    ",dp[n]);continue;}
    
              printf("%d
    ",dp[n]);
    
    
    
        }
    
    }

      问题十六(uva 10213):

      有多少土地:

      在一个椭圆的土地当中,在边界上有n个点,现在连接任意的两个点,那么请问这块椭圆土地能够最多被分割成多少块?

      分析:一道欧拉定理即视感非常强的题目,我们依然要借助节点v、边的个数e来确定面数f,在这里要去掉最外面那个面,即在这道具体的题目当中,f = e-v+1.

      那么下面的问题还是求v、e。其实这里能够看到已经和计算几何不沾什么边了,本质上来讲是一个组合计数问题。

                             

      点:

      我们固定一条线段的起始点,然后遍历剩余点作为终点,状态参量i表示该线段左边的点的个数,这是一个子问题,我们遍历起始点,然后进行去重(充分理解这个分割状态的过程,能够看到每个点会被计算4次)就可以了。

       

      边:

      基于求点数的穷举计数方法,这里计算边会变得非常简单。

       

      但是很遗憾这个问题到这里还没有结束,由于这道题目是多组数据,而且在时间复杂度上卡的很近,因此我们需要继续的化简。

     

      对于一个样例,给出n,我们给出的公式是O(n)算法(循环计算),下面尝试将其优化成O(1)。

      参考代码如下:

     import java.math.BigInteger;
    import java.util.Scanner;
    
    public class main {
        public static void main(String[] args) {
            int t;
            Scanner in = new Scanner(System.in);
            t = in.nextInt();
            for(int Case =1 ;Case <= t;Case++)
            {
            
            
            
            BigInteger n = in.nextBigInteger();
            BigInteger a = n.pow(4);
            BigInteger b = n.pow(3).multiply(BigInteger.valueOf(6));
            BigInteger c = n.pow(2).multiply(BigInteger.valueOf(23));
            BigInteger d = n.multiply(BigInteger.valueOf(18));
            
            BigInteger ans = BigInteger.valueOf(0);
            
            ans = ans.add(a).subtract(b).add(c).subtract(d);
            ans = ans.divide(BigInteger.valueOf(24));
            ans = ans.add(BigInteger.valueOf(1));
            System.out.println(ans);
    
            
               
            }
        }
    
    }
  • 相关阅读:
    2、容器初探
    3、二叉树:先序,中序,后序循环遍历详解
    Hebbian Learning Rule
    论文笔记 Weakly-Supervised Spatial Context Networks
    在Caffe添加Python layer详细步骤
    论文笔记 Learning to Compare Image Patches via Convolutional Neural Networks
    Deconvolution 反卷积理解
    论文笔记 Feature Pyramid Networks for Object Detection
    Caffe2 初识
    论文笔记 Densely Connected Convolutional Networks
  • 原文地址:https://www.cnblogs.com/rhythmic/p/5441902.html
Copyright © 2011-2022 走看看