【DP】奶牛家譜 Cow Pedigrees
阿新 • • 發佈:2018-12-13
題目描述
農民約翰準備購買一群新奶牛。 在這個新的奶牛群中, 每一個母親奶牛都生兩個小奶牛。這些奶牛間的關係可以用二叉樹來表示。這些二叉樹總共有N個節點(3 <= N < 200)。這些二叉樹有如下性質:
每一個節點的度是0或2。度是這個節點的孩子的數目。
樹的高度等於K(1 < K < 100)。高度是從根到最遠的那個葉子所需要經過的結點數; 葉子是指沒有孩子的節點。
有多少不同的家譜結構? 如果一個家譜的樹結構不同於另一個的, 那麼這兩個家譜就是不同的。輸出可能的家譜樹的個數除以9901的餘數。
輸入輸出格式
輸入格式:
兩個空格分開的整數, N和K。
輸出格式:
一個整數,表示可能的家譜樹的個數除以9901的餘數。
輸入輸出樣例
輸入樣例#1:
5 3
輸出樣例#1:
2
有時候計算一下無用的狀態反而是有用的。例如樓下的全都是設dp[i][j]表示i個點剛好j層的方案數,然後弄個4層迴圈,還有組合數什麼亂七八糟的,不僅思維難度高,程式設計難度高,時空複雜度都高!
既然設剛好j層那麼麻煩,我們不妨設dp[i][j]表示i個點小於等於j層的方案數,那麼最終我們所需的答案就是dp[n][k]-dp[n][k-1]是不是?
考慮一下dp過程(一般樹形揹包,除非是多叉樹用分組揹包只能用dfs寫,否則可以先考慮寫一個記憶化搜尋,因為記憶化搜尋雖然效率低一些,但是思維複雜度較低,初始化考慮也會更全面,然後對應的再改寫成dp)
列舉一個t,表示分t個點給左子樹,剩下i-t-1(除去當前的根)分給右子樹,然後乘法原理搞一搞。
即:dp[i][j]=sigma(dp[t][j-1]*dp[i-t-1][j-1]),是不是很簡單?
考慮一下初始化:把dp[1][]都設成1就好了,然後列舉點的個數時只需要列舉奇數(這個很容易想到)。
參考程式碼:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int Mod=9901; int dp[210][110],n,k; int main(){ scanf("%d%d",&n,&k); for (int i=1;i<=k;i++)dp[1][i]=1; for (int tk=1;tk<=k;tk++) for (int i=3;i<=n;i+=2) for (int j=1;j<i;j+=2) (dp[i][tk]+=dp[j][tk-1]*dp[i-j-1][tk-1])%=Mod; printf("%d",(dp[n][k]-dp[n][k-1]+Mod)%Mod); return 0; }