題目:點擊開啟連結
遞推問題實現起來很簡單,但得到遞推公式確實很麻煩,就像DP一樣。
分析(部分出自HDU的PPT):
設:F(n)表示n個人的合法隊列,則:
按照最後一個人的性別分析,他要麼是男,要麼是女,所以可以分兩大類討論:
1、如果n個人的合法隊列的最後一個人是男,則對前面n-1個人的隊列沒有任何限制,他只要站在最後即可,所以,這種情況一共有F(n-1);
2、如果n個人的合法隊列的最後一個人是女,則要求隊列的第n-1個人務必也是女生,這就是說,限定了最後兩個人必須都是女生,這又可以分兩種情況:
(1)、如果隊列的前n-2個人是合法的隊列,則顯然後面再加兩個女生,也一定是合法的,這種情況有F(n-2);
(2)痛點在於,即使前面n-2個人不是合法的隊列,加上兩個女生也有可能是合法的,當然,這種長度為n-2的不合法隊列,不合法的地方必須是尾巴,就是說,這裡說的長度是n-2的不合法串的形式必須是“F(n-4)+男+女”,這種情況一共有F(n-4).
所以遞推公式為F(n)=F(n-1)+F(n-2)+F(n-4).
另外需要注意的是 這個遞推式的資料範圍到了1000,int甚至long long 都已經無法承載最大邊界,所以我使用了前兩天貼出的大數類。
#include<iostream> #include<string> #include<iomanip> #include<algorithm> using namespace std; #define MAXN 9999#define MAXSIZE 10#define DLEN 4class BigNum{ private: int a[500]; //可以控制大數的位元 int len; //大數長度public: BigNum(){ len = 1;memset(a,0,sizeof(a)); } //建構函式BigNum &operator=(const BigNum &); //重載賦值運算子,大數之間進行賦值運算BigNum operator+(const BigNum &) const; //重載加法運算子,兩個大數之間的相加運算 void print(); //輸出大數}; BigNum & BigNum::operator=(const BigNum & n) //重載賦值運算子,大數之間進行賦值運算{int i;len = n.len;memset(a,0,sizeof(a)); for(i = 0 ; i < len ; i++) a[i] = n.a[i]; return *this; }BigNum BigNum::operator+(const BigNum & T) const //兩個大數之間的相加運算{BigNum t(*this);int i,big; //位元 big = T.len > len ? T.len : len; for(i = 0 ; i < big ; i++) { t.a[i] +=T.a[i]; if(t.a[i] > MAXN) { t.a[i + 1]++; t.a[i] -=MAXN+1; } } if(t.a[big] != 0)t.len = big + 1; elset.len = big; return t;}void BigNum::print() //輸出大數{ int i; cout << a[len - 1]; for(i = len - 2 ; i >= 0 ; i--){ cout.width(DLEN); cout.fill('0'); cout << a[i]; } cout << endl;}BigNum que[1202];//上邊不是主要作用。。int main(){que[0]=1;que[1]=1;que[2]=2;que[3]=4;for(int i=4;i<=1000;i++){que[i]=que[i-1]+que[i-2]+que[i-4];}int tar;while(cin>>tar){que[tar].print();}return 0;}