c語言排列組合還可以這樣求
本文主要講程式設計比賽中常用的排列組合。
首先,排列組合的公式是(其中P代表的就是A)
最普通的演算法就是按照公式求了,即分子算出來,分母算出來,然後相除,寫成程式碼為:
int c( int m,int n )
{
int a = 1,b = 1, c = 1;
for( int i = 1 ; i <= m ; i++ )
a = a*i;
for( int i = 1 ; i <= n ; i++ )
b = b*i;
for( int i = 1 ; i <= m-n ; i++ )
c = c*i;
return a/(b*c);
}
很顯然,這種方法不好,很容易溢位,只要資料範圍一大,就不能行了。
實際上,我們自己在紙上算排列組合的時候也並不是按照公式老老實實的算,其實可以化簡,即約分。
比如c(5,4)按照原來的方法=A(5,4)/!4,其實c(5,4)=c(5,1)= 5/1 = 1;
那麼就是c(m,n)= m*(m-1)*.......(m-n+1) / ! n 。
寫成程式碼為:
int c( int m,int n ) { int a = 1,b = 1; n = min(n,m-n); //求簡單一點的 例如C(5,4) 可以求C(5,1) if( n == 0 ) return 1; for( int i = m ; i >=m-n+1 ; i-- ) a = a*i; for( int i = 1 ; i <= n ; i++ ) b = b*i; return a/b; }
這個方法相對於上一個好一點,但是還是有問題,資料太大會溢位,而且不能進行取模運算(反正我不知道)。
那麼,再介紹一種方法,遞推的思想,
其實排列組合還是挺有規律的,例如下面的
(1,1) (1,2) (1,3) (1,4) (1,5) (1,6)
1 2 3 4 5 6
(2,2) (2,3) (2,4) (2,5) (2,6)
1 3 6 10 15
(3,3) (3,4) (3,5) (3,6)
1 4 10 20
(4,4) (4,5) (4,6)
1 5 15
(5,5) (5,6)
1 6
(6,6)
1
因為具有對稱性,我只列了一半,高中書本里介紹過楊輝三角,其實很簡單,就是c(n,m)=c(n,m-1)+c(n-1,m-1),對應到上幅圖中就是:某一個 等於 這個的左邊的 加上 這個左邊的上邊的。即C(2,3) = C(2,2)+C(1,2)那麼我們先把第一層算出來,然後遞推第二層,然後遞推。這種方法的優點是一次就把所有的求出來了,而且中間可以進行取模運算。
我們用一個二維陣列來儲存結果。
程式碼如下:
int a[1001][1001];
//陣列的大小隨實際情況而定
//陣列的型別最好為 long long
void c( )
{
memset(a,0,sizeof(a));
for( int i = 1 ; i <= 1000 ; i++ ) //對第一層初始化 , 範圍視情況而定
a[1][i] = i,a[0][i] = 1;
for( int r = 2 ; r <= 1000 ; r++ ) //列舉行
for( int c = r ; c <= 1000 ; c++ ) //列舉列
{
a[r][c] = a[r][c-1]+a[r-1][c-1];
/*
if( a[r][c] > mo )
a[r][c] = a[r][c] % mo; 取模運算
一般題目都會給一個mo,讓你取模
*/
}
}
本文只講了C(m,n),沒有講A(m,n),實在是能力有限,以後學到相關知識一定補充!