母函数与排列组合-程序员宅基地

                      母函数与排列组合

  在谈论母函数问题之前,我们先看一个简单的问题描述:假如有两组数据(A,B)和(C,D),每组中选出一个构成一个组合,总共有几种选法?很显然总共有4种选法:AC,AD,BC,BD。而且很容易联想到这个式子(A+B)*(C+D)=A*C+A*D+B*C+B*D。式子中的几个乘积项就是上面的4种选法。假如把问题换一下:每组中选出一个或0个数据构成组合,总共有几种组合?那么结果就变成:{空},A,B,C,D,AC,AD,BC,BD,而式子(1+A+B)*(1+C+D)=1+C+D+A+A*C+A*D+B+B*C+B*D,正好和上面组合的结果又一致(1代表什么都没选)。从这2个例子我们可以发现多项式乘积和组合存在着某种关系。事实上我们可以这么理解:(1+A+B)可以理解为从第一组数据中取0个数据,取A或者取B,同样(1+C+D)可以理解为从第二组数据取0个数据,取C或者取D。两者相乘的结果就表示了所有的组合。再看一下这个多项式:

  (1+x)*(1+x+x2)*(1+x3)=1+2x+2x2+2x3+2x4+2x5+x6

  这个多项式和上面的有一些区别了,它的幂级数超过1了。如果要从(1+x)、(1+x+x2)和(1+x3)中得到x的2次方的话,有两种选择:从(1+x)和(1+x+x2)中分别选择一个x或者从(1+x+x2)中选择x2;如果要得到x的6次方的话,只有1种选择,就是从(1+x)中选择x、(1+x+x2)中选择x2、(1+x3)中选择x3。也就是说乘积结果的每一项anxn的前面的系数an表示了从(1+x)、(1+x+x2)和(1+x3)中得到xn的组合数。

  其实上面的例子就利用了母函数的思想,下面来具体讨论一下母函数。

一.什么是母函数

  下面这个对于母函数的描述摘自维基百科:

  在数学中,某个序列 的母函数是一种形式幂级数,其每一项的系数可以提供关于这个序列的信息。

  也就是说母函数是针对某个序列的,它的外在表现形式是一种形式幂级数。比如说有这样一个序列a0,a1,......an,构造一个函数

  f(x)=a0+a1x+a2x2+......+anxn

  则f(x)是序列a0,a1,......an的母函数。比如说最常见的(1+x)n,它是序列C(n,0),C(n,1),C(n,2)...C(n,n)的母函数。

  母函数包括几种,其中最常见的是普通型母函数和指数型母函数。普通型母函数是形如 f(x)=a0+a1x+a2x2+......+anxn的函数,而指数型母函数是形如G(x) = a0 + a1*(x)/1! + a2*(x2)/ 2! + a3*(x3)/3! + …… an*(xn)/k!的函数。

二.利用普通型母函数解决组合问题

 利用母函数的思想可以解决很多组合问题,下面举例说明:

 1.口袋中有白球2个,红球3个,黄球1个,从袋中摸出3个球有几种取法?

    和上面描述的例子类似,我们可以用次数代表球的个数,多项式的每一项前面的系数代表取法的种树。

  可以很容易地写出下面这个式子:

  (1+x+x2)(1+x+x2+x3)(1+x)

   (1+x+x2)表示有白球2个,1表示白球不取,x代表取1个白球,x2代表取2个白球,即用x的次数表示取球的个数,后面的也是类似。那么这个多项式的乘积就把所有的情况都表示出来了,对于最终乘积的每一项anxn,表示取n个球有an种取法。

    2.有若干个1克,2克,5克的砝码,要称出20克的重量,有多少种称法?

  这里不限制砝码的个数,无所谓,照样写出母函数:

  (1+x+x2+x3+......xk+....)(1+x2+x4+x6......+x2n+......)(1+x5+x10+......x5m+......)

  因为要称出20克,所以只需要找找到结果中次数为20 的那一项就可以得到结果。

    3.同样对于正数划分也可以解决,比如有整数20,划分成1,2,5,有多少种划分方法?

  解法和2的类似。

     还有一类题目和这类似,有n个球放到m个盒子中,有多少种不同的放法?

    (1+x+x2+x3+...xk+...)(1+x+x2+x3+...xk+...)(1+x+x2+x3+...xk+...)总共有m项,然后找出乘积中次数为n的那一项系数。

三.利用指数型母函数解决排列问题

  1.口袋中有白球2个,红球3个,黄球1个,任取3个作为一个排列,总共有多少种排列?

  类似地用指数型母函数解决

  用(1+x/1!+x2/2!)表示取白球0个,1个或者2个

  那么(1+x/1!+x2/2!)(1+x/1!+x2/2!+x3/3!)(1+x/1!)来表示所有的排列结果。

   =1+3x+4x2+19x3/6+19x4/12+6x5/12+x6/12

   =1+3*(x/1!)+8*(x2/2!)+19*(x3/3!)+38*(x4/4!)+60*(x5/5!)+60*(x6/6!)

  找到次数为3的那一项,系数为19,那么总共有19种排列。

  2.用1,2,3,4能够组成多少个5位数,要求1出现2次或者3次,2出现0次或者1次,3没有限制,4只出现偶数次。

  (x2/2!+x3/3!)(1+x)(1+x/1!+x2/2!+x3/3!+.....xk/k!+....)(1+x2/2!+x4/4!+......+x2n/(2n)!+......)

   每个式子的含义就不多解释了,读者应该能看懂它的含义。最终的结果就是x5/5!这一项的系数。

  用代码去实现母函数的计算过程很简单,它是模拟我们人工计算多项式乘积的过程,比如有多项式H1*H2*H3......

  我们先计算H1和H2的乘积,得到结果H',再用H'和H3相乘......依次类推下去,直到得到最终的结果。

下面这道题目是航电上的一道题:

题目意思是有1分,2分,5分的硬币各a,b,c枚,求算不能组成的总钱数的最小值。

http://acm.hdu.edu.cn/showproblem.php?pid=1085

#include <iostream>
using namespace std;


int main(int argc, char *argv[])
{
    int num[3];
    int cent[3]={
    1,2,5};          //次数增长步长 
    while(scanf("%d %d %d",&num[0],&num[1],&num[2]) != EOF)
    {
        if(num[0]==0&&num[1]==0&&num[2]==0)
            break;
        int i,j,k;
        int c[8001],tempC[8001];     //因为三种硬币最多1000枚,1*1000+2*1000+5*1000=8000,那么多项式乘积的最高次数为8000 
                                     //c保存累计相乘各项的系数,tempC保存c和当前项相乘的系数 
                                           //c[i] 表示次数为i的那一项的系数
                                      
         int max=num[0]+2*num[1]+5*num[2];   //求出该组输入条件下的最高次数 
        
         for(i=0;i<=8001;i++)   
         {
            c[i]=0;
            tempC[i]=0;
         }
        
        
        //母函数为(1+x+x^2+...x^num[0])(1+x^2+x^4+....x^2*num[1])(1+x^5+x^10+...+x^5*num[2]) 
        for(i=0;i<=cent[0]*num[0];i+=cent[0])   //第一个多项式的系数初始化 
        {
            c[i]=1;
        }
        
        for(i=1;i<3;i++)    //i表示总共有多少个多项式 
        {
            for(j=0;j<=max;j++)    //累计相乘的x^j的系数 
            {
                for(k=0;k+j<=max && k<=cent[i]*num[i];k+=cent[i])   //当前项x^k的系数 
                {
                    tempC[k+j]+=c[j];   //x^j * x^k=x^(j+k)
                }
            }
            
            for(j=0;j<=max;j++)    //将临时数组清零 
            {
                c[j]=tempC[j];
                tempC[j]=0;
            }
        }
        
        for(i=0;i<=max;i++)
        {
            if(c[i]==0)
                break;
        }
        printf("%d\n",i);
    }
    return 0;
}

转载于:https://www.cnblogs.com/dolphin0520/archive/2012/11/07/2755080.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30508241/article/details/99667312

智能推荐

缓存穿透与布隆过滤器_缓存穿透 布隆过滤器-程序员宅基地

文章浏览阅读1.7k次。本文主要介绍在使用缓存过程中经常会遇到的几个问题:缓存击穿、缓存雪崩、缓存穿透,以及其解决方案。之后会对缓存穿透的解决方案之一布隆过滤器,进行详细讲解。_缓存穿透 布隆过滤器

pandas写入oracle,python pandas dataframe 读取和写入Oracle-程序员宅基地

文章浏览阅读1.4k次。1、代码:主要写入时表要为小写,否则报错Could not reflect: requested table(s) not available in Enginefrom sqlalchemy import create_engineconn_string='oracle+cx_oracle://admin:[email protected]:1521/ORCL?charset=utf8'..._pandas cx_oracle 写入

react-dnd拖拽表单组件列表实例_const defaultlist =-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏2次。API 学习:https://blog.csdn.net/gaofeng6565/article/details/115696823项目准备:https://codepen.io/选择React,AntDesign 模式,添加依赖 react-dnd(@14.0.2),react-dnd-html5-backend(@14.0.0)ListDrag.jsimport React, { useState } from "react";import { Button } from "antd"._const defaultlist =

无人驾驶之MATLAB无人驾驶工具箱学习(1)_ego vehicle-程序员宅基地

文章浏览阅读2.4w次,点赞21次,收藏162次。更新完显卡驱动后,视频可以自动导入了,继续码。2018.08.111 坐标系转换ADST(Automated Driving System Toolbox)中的坐标系ADST中的坐标系:世界坐标系(world),所有车辆及其传感器都建立其上的固定坐标系。 车辆(Vechicle):固定在车身上。有代表性地,车辆坐标系建立在车辆后轴中点处的地面上。 传感器(Sensor):明确具..._ego vehicle

SAP S/4 HANA新变化-FI数据模型-程序员宅基地

文章浏览阅读370次。SAP S/4 HANA新变化-FI数据模型 http://mp.weixin.qq.com/s?__biz=MzAwMjgyMTA4MQ==&mid=2652153162&idx=1&sn=aee6fc43e0577479854e4842df919c90&ch..._hana anlc

Centos7(腾讯云)安装UniFi控制器_centos unifi-程序员宅基地

文章浏览阅读989次。腾讯云主机,就自行度娘吧,没什么好说的。用SSH连接上云主机(root)用户登陆。关闭防火墙 systemctl stop firewalld.service systemctl disable firewalld.service添加mongodb源vim /etc/yum.repos.d/mongodb-org-4.4.repo添加以下内容到mongodb-org.repo[mongodb-org-4.4]name=MongoDB Repository.._centos unifi

随便推点

Java使用LocalDate获取某个月的第一天和最后一天日期_localdate获取当月最后一天-程序员宅基地

文章浏览阅读3.8w次,点赞33次,收藏80次。Java使用LocalDate或LocalDateTime获取某个月的第一天和最后一天日期_localdate获取当月最后一天

银河麒麟ARM64 飞腾FT2000 linuxdeployqt linux打包qt_linuxdeployqt aarch64-程序员宅基地

文章浏览阅读6.2k次,点赞3次,收藏40次。银河麒麟ARM64 飞腾FT2000 linuxdeployqt linux打包qt下载linuxdeployqt-aarch64.AppImageqt版本说明linuxdeployqt打包准备编译好的程序插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载linuxdeployqt-aa_linuxdeployqt aarch64

在Springboot集成Activiti工作流引擎-引入、调用,测试【基础讲解】-程序员宅基地

文章浏览阅读1.6k次,点赞2次,收藏6次。工作流 通过计算机对业务流程自动化执行管理他主要解决的是使在多个参与者之间按照某种“预定义规则”自动进行传递稳定 信息或任务的过程通俗来讲 业务上一个玩着的审批流程 比如请假,出差 外出采购等工作流引擎就是来解决流程问题的 提高我们的工作效率如果没有工作流引擎 我们就需要自己去写逻辑 就特别的复杂 扩展性还不强使用工作流引擎 业务改变,不需要修改代码如果是我们自己写的逻辑 有可能 业务改变,代码也需要改变那么为什么工作流引擎不用修改代码因为我们的工作流引擎都实现了一个规范这个规范要_集成activiti

Python爬虫:xpath,cookie都正确仍然无法爬取需要的内容解决方法之一_xpath写的都对 为什么抓不到内容-程序员宅基地

文章浏览阅读2.1k次,点赞2次,收藏10次。经过很多次尝试以及仔细观察所爬取的html代码内容,我发现有一个标签里含有的css代码:style = display:none ,这行代码可以把这个标签里面的内容隐藏。展开这个标签里面的内容,很可能就是我们所需要的真实的页面a标签里面的url地址。注意,这里说了一般,有些网站的反爬措施很高级,甚至会封掉你的ip。看这篇文章的猿猿们肯定有了一定的python-xpath爬虫基础了,后面对li_tree的处理以及延伸获取所需要的页面内容我在这就不介绍啦!这样我们就得到了正确的li_tree。_xpath写的都对 为什么抓不到内容

iOS开发常用的RGB色值和中文名字_苹果远峰蓝的rgb-程序员宅基地

文章浏览阅读633次。RGB值 RGB值 RGB值黑色000#000000黄色2552550#FFFF00浅灰蓝色176_苹果远峰蓝的rgb

SpringBoot+Mysql+小程序实现的美团外卖美食小程序系统附带前台和后台代码_美团前端微信小程序代码-程序员宅基地

文章浏览阅读778次。随着数字化技术兴起,各种应用软件覆盖各行各业,大大推动了产业发展。然而,在外卖点餐领域,现实问题仍然存在,例如订单处理效率低、库存管理复杂、客户服务水平不一以及数据分析能力不足等。为解决这些问题,本文研发了一款基于微信小程序与Spring Boot的外卖点餐系统,旨在提升效率和管理水平,优化顾客体验。本外卖订餐系统融合了先进技术与实践,采用Spring Boot框架开发后端,借助MySQL数据库存储数据,并通过微信小程序实现用户端。系统的创新表现在全面提升了管理效率和顾客服务。_美团前端微信小程序代码