筆試小技巧--隔板法解排列組合問題(附程式碼)

li27z發表於2017-05-05

引言

各大網際網路公司的春季招聘都在如火如荼地進行著,在筆試環節,除了考察應聘者(技術崗)的資料結構、計算機網路等計算機基礎知識外,也不乏一些有趣的數學問題,例如:

一道阿里巴巴2017春季實習生招聘筆試選擇題,大意是:一名程式設計師需要在週一至週五5天的工作日裡需要提交7次程式碼,問有多少種提交方案?

針對此類同素分堆問題,我們可以運用隔板法來解決。

理解隔板法

隔板法就是在n個元素間的(n-1)個空中插入k個板,可以把n個元素分成k+1組的方法。  

應用隔板法必須滿足3個條件:   
(1) 這n個元素必須互不相異;
(2) 所分成的每一組至少分得1個元素;
(3) 分成的組別彼此相異。

例1. 求方程 x+y+z=10的正整數解的個數。
分析:將10個球排成一排,球與球之間形成9個空隙,將兩個隔板插入這些空隙中(每空至多插一塊隔板),規定由隔板分成的左、中、右三部分的球數分別為x、y、z之值(如下圖)。則隔法與解的個數之間建立了一一對立關係,故解的個數為C(9,2)=36(個)。

這裡寫圖片描述

例2. 求方程 x+y+z=10的非負整數解的個數。(新增球數用隔板法)
分析:注意到x、y、z可以為零,故例1解法中的限定“每空至多插一塊隔板”就不成立了,怎麼辦呢?只要新增三個球,給x、y、z各新增一個球,這樣原問題就轉化為求 x+y+z=13的正整數解的個數了,易得解的個數為C(12,2)=66(個)。

例3. 將20個相同的小球放入編號分別為1,2,3,4的四個盒子中,要求每個盒子中的球數不少於它的編號數,求放法總數。(減少球數用隔板法)
分析:先在編號1,2,3,4的四個盒子內分別放0,1,2,3個球,剩下14個球,有1種方法;再把剩下的球分成4組,每組至少1個,由例1知方法有C(13,3)=286(種)。

可見,利用隔板法我們可以非常簡便地解決此類排列組合問題。

程式碼實現

以上問題可以抽象為:將n個相同的球放入m個盒子中(編號依次為1,2,…,m),盒子中的球數可以為0,輸出所有的放置方法及方法數。

思路:
這裡寫圖片描述

程式碼如下:

#include <stdio.h>

int count = 0;

void f(int* r, int* p, int n, int m)
{
  if(m == 1)
  {
    ++count;

    for(; r != p; ++r)
    {
      printf("%d", *r);
    }
    printf("%d\n", n);   
  }
  else
  {
    for(*p = 0; *p <= n; ++*p)
    {
      f(r, p + 1, n - *p, m - 1);
    }
  }
} 

void g(int n, int m)
{
  int r[m];
  f(r, r, n, m);
}

int main()
{
  int n, m;
  printf("Please input the number of balls:\n");
  scanf("%d", &n);
  printf("Please input the number of boxes:\n");
  scanf("%d", &m);
  g(n, m);
  printf("The number of solutions:%d\n", count);
  return 0;
}

執行截圖:
這裡寫圖片描述


參考資料:
n個球放入m個盒子,使用程式輸出所有的放法? https://www.zhihu.com/question/51448931

相關文章