給出一棵多叉樹,每個結點的任意兩個子結點都有左右之分。從根結點開始,每次儘量往左走,走不通了就回溯,把遇到的字母順次記錄下來,可以得到一個序列。如圖2-6所示的5 個圖的序列均爲ABABABA 。給定一個序列,問有多少棵樹與之對應。
【輸入格式】
輸入包含多組數據。每組數據僅一行,即由大寫字母組成的訪問序列。序列非空,且長度不超過300 。輸入結束標誌爲文件結束符(EOF) 。
【輸出格式】
對於每組數據,輸出滿足條件的多叉樹的數目除以10^9 的餘數。
【分析】
設輸入序列爲S,d(i,j)爲子序列Si,Si+1,.....Sj與對應的樹的個數,則邊界條件是d(i,i)=1,且Si 不等於Sj時d(i,j)=0( 因爲起點和終點應是同一點)。在其他情況下,設第一個分支在Sk 時回到樹根(必須有Si = Sk) ,則這個分支對應的序列是Si+1,...Sk-1,方案數爲d(i+1,k-1);
其他分支對應的訪問序列爲Sk,...Sj,方案數爲d(kJ) 。這樣,在非邊界情況,遞推關係爲
,如圖2-7 所示。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 300 + 10;
const int MOD = 1000000000;
typedef long long LL;
char S[maxn];
int d[maxn][maxn];
int dp(int i, int j) {
int& ans = d[i][j];
if(ans >= 0) return ans;
if(i == j) return ans = 1;
if(S[i] != S[j]) return ans = 0;
ans = 0;
for(int k = i+2; k <= j; k++) if(S[i] == S[k])
ans = (ans + (LL)dp(i+1,k-1) * (LL)dp(k,j)) % MOD;
return ans;
}
int main() {
while(scanf("%s", S) == 1) {
memset(d, -1, sizeof(d));
printf("%d\n", dp(0, strlen(S)-1));
}
return 0;
}