題目連接:https://leetcode-cn.com/leetbook/read/didiglobal2/e7hh2i/
題目來源:力扣(LeetCode)ios
題目描述:數組
給定三種類型的小球 P、Q、R,每種小球的數量分別爲 np、nq、nr 個。如今想將這些小球排成一條直線,可是不容許相同類型的小球相鄰,問有多少種排列方法。如若 np=2,nq=1,nr=1 則共有 6 種排列方式:PQRP,QPRP,PRQP,RPQP,PRPQ 以及 PQPR。若是沒法組合出合適的結果,則輸出 0。spa
輸入描述:
一行以空格相隔的三個數,分別表示爲 np,nq,nr。code
輸出描述:blog
排列方法的數量。遞歸
輸入樣例:
2 1 1ci
輸出樣例:
6leetcode
解題思路:io
按排列中第一個小球的類型不一樣(P、Q或R),可將排列分爲三類。總排列數爲三類排列數的總和。設總的合法排列數爲fall,第一個球爲P的合法排列數爲fp(np, nq, nr),第一個小球爲Q的合法排列數爲fq(np, nq, nr),第一個小球爲R的合法排列數爲fr(np, nq, nr)。則有:class
fall = fp(np, nq, nr) + fq(np, nq, nr) + fr(np, nq, nr)
對於fp(np, nq, nr):
1. 若np <= 0,此時沒法取出一個P小球放到排列的第一位,所以第一個球爲P的合法排列數爲0。
2. 若np == 1且nq == 0, nr == 0,此時取出一個P小球放到排列第一位之後,全部的小球都已用盡且不會有相同的小球相臨。所以合法的排列數爲1。
3. 若爲其它狀況,在取出一個P小球放到排列第一位之後,剩餘的小球爲:np - 1個P小球,nq個Q小球,nr個R小球。要使排列合法,在對剩餘小球進行排列時,須要將Q球或者R球放在第一位並保證後續排列合法,所以此時有:fp(np, nq, nr) = fq(np - 1, nq, nr) + fr(np - 1, nq, nr)。
對於fq(np, nq, nr)與fr(np, nq, nr)可作相似的分析。
至此,可經過將原來的問題一步步分解成規模更小的相同問題進行遞歸求解。經過一個輔助的多維數組記錄遞歸過程當中產生的重複狀態來提升運算效率。代碼以下:
#include <iostream> #include <vector> using namespace std; int64_t fp(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec); int64_t fq(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec); int64_t fr(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec); int64_t fp(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec) { if (np <= 0) return 0; if (np == 1 && nq == 0 && nr == 0) return 1; if (rec[0][np][nq][nr] == -1) { rec[0][np][nq][nr] = fq(np - 1, nq, nr, rec) + fr(np - 1, nq, nr, rec); } return rec[0][np][nq][nr]; } int64_t fq(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec) { if (nq <= 0) return 0; if (np == 0 && nq == 1 && nr == 0) return 1; if (rec[1][np][nq][nr] == -1) { rec[1][np][nq][nr] = fp(np, nq - 1, nr, rec) + fr(np, nq - 1, nr, rec); } return rec[1][np][nq][nr]; } int64_t fr(int np, int nq, int nr, vector<vector<vector<vector<int64_t> > > >& rec) { if (nr <= 0) return 0; if (np == 0 && nq == 0 && nr == 1) return 1; if (rec[2][np][nq][nr] == -1) { rec[2][np][nq][nr] = fp(np, nq, nr - 1, rec) + fq(np, nq, nr - 1, rec); } return rec[2][np][nq][nr]; } int main() { int np, nq, nr; cin >> np >> nq >> nr; vector<vector<vector<vector<int64_t> > > > rec(3, vector<vector<vector<int64_t > > >(np + 1, vector<vector<int64_t> >(nq + 1, vector<int64_t>(nr + 1, -1)))); int64_t res = fp(np, nq, nr, rec) + fq(np, nq, nr, rec) + fr(np, nq, nr, rec); cout << res << endl; //system("pause"); return 0; }
總結:
應該是個基礎的動態規劃題目吧,代碼寫得確實有點爛,不過懶得改了,就這樣,再接再勵吧。