對酒當歌,人生幾何。譬如朝露,去日苦多
阿新 • • 發佈:2019-02-06
今天把常用數學公式用C/C++表達組織一下,以便日後使用。
排列組合數
先來看看排列組合數的公式:
顯然寫程式的話,
// 排列組合數
#define uint unsigned int
// 函式名稱: Anm
// 函式功能: 從n中取m的全排列數
uint Anm(uint n, uint m)
{
uint sum = 1 , i = 1;
for(i=n; i>= (n-m+1); i--)
sum *= i;
return (sum);
}
// 函式名稱: Cnm
// 函式功能: 從n中取m的組合數
uint Cnm(uint n, uint m)
{
uint i = 1, sum = 1;
for(i=1; i<=m; i++)
sum = sum * (n+1-i)/i; // 千萬不可錯寫成了 sum *= (n+1-i)/i;
/*
* 千萬不可錯寫成了 sum *= (n+1-i)/i;
* 因為後者會先計算分式,會導致整數互質除不盡的錯誤
*/
return (sum);
}
隨機輸出任意一個全排列
// 函式名稱: RandArrange
// 函式功能: 在指定範圍內輸入任意的一個全排列
#include <algorithm>
#include <time.h>
#define uint unsigned int
void RandArrange(uint* uiResTbl, uint rangeMin, rangeMax)
{
// Seed the random-number generator with the current time so that
// the numbers will be different every time we run.
srand((uint)time(NULL));
uint nCnt = rangeMax - rangeMin + 1;
uint uiRand, i, j;
i = j = 0;
memset(uiResTbl, -1, nCnt);
while(i < nCnt)
{
j = 0;
uiRand = (double)rand() / (RAND_MAX + 1) * (rangeMax + 1 - rangeMin) + rangeMin;
while(j < i)
{
if(uiResTbl[j] == uiRand) break;
j++;
}
if(i != j)
continue;
uiResTbl[i] = uiRand;
i++;
}
}
十分值得注意的是,此函式並不穩定,產生滿足要求的全排列的時間不定。
隨機輸出一組全排列的情況在實際的模擬中用得比較多,如從某資料集中隨機選取指定數目的樣本。(顯然這是一種簡單的求部分全排列)而MATLAB中有現成的輸出隨機全排列的函式 randperm
在MATLAB命令視窗中Help randperm函式:
與上面這個 RandArrange函式不同的是,MATLAB中的randperm函式是輸出從1到n的一組隨機全排列,不能指定下限。