題意: 定義一種結構叫做S-tree,給定深度n,S-tree是一顆深度爲n(n<=7)的滿二叉樹(根節點深度爲0),樹節點上標記着變量的名字,並且樹的同一層上的變量名相同,葉子節點爲1,或者0。例如給定深度爲3的兩顆樹
所以表達一棵樹只需要給出變量序列和葉子節點即可,左邊的樹可以表達爲
x1 x2 x3 00000111
右邊的樹表達爲:
x3 x1 x2 00010011
x1, x2, x3通過VVA(Variable Values Assignment)賦值, 例如VVA=110對於第一個圖表示x1 = 1, x2 =1, x3 = 1,對於第二個圖表示x3 = 1, x1 = 1, x2 = 0。
給定S-tree和VVA,定義一種遍歷樹的方法,對於樹中的節點變量,如果變量爲0,則走左子樹,變量爲1則走右子樹,那麼對於VVA=110,左邊的樹遍歷到從左往右倒數第二個葉子節點。
題目給定多個S-tree,和VVA,問遍歷結果
思路: 可以按照樹的遍歷去做,這樣思路直接。但是可以看到最後遍歷樹只需要知道走到哪一個葉子節點即可。
二分思路來源在於:走左子樹,則最終結果一定不在葉子節點的右半側,走右子樹,最終結果一定不在葉子節點的左半側,如此設定start,end指定搜索下標的範圍,不斷縮小範圍,同時需要配上手工先行驗證想法。
深度爲n的樹,葉子節點有個,用數組char terminal_node[150]
存儲,只需要找到遍歷最後的下標index即可。設葉子節點數組下標從1開始存放數字,且start=1,end=,mid=(start+end)/2。對於給定的VVA,遍歷前n-1個VVA的值,如果某個變量爲0,走左子樹,那麼最終的值不可能在mid右邊,那麼修改end=mid,mid=(start+end)/2,如果變量爲1同理,不可能在mid左邊,修改start=mid,mid=(start+end)/2,按照這個步驟最終遍歷完n-1個VVA,如果第n個VVA的值爲0,則index = mid即爲最終結果在葉子節點的下標,如果VVA=1,則index = mid+1,最後結果爲terminal_node[index]
代碼
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
//Accepted
int pow(int x, int y) {
int result = 1;
for (int i = 0; i < y; i++)
result *= x;
return result;
}
int s_tree_function(char vva[], int n) {
int start = 1, end = (int)pow(2, n);
int mid = (start + end) / 2;
for (int i = 0; i < n - 1; i++) {
if (vva[i] == '0') {
end = mid;
mid = (start + mid) / 2;
}
else {
start = end;
mid = (end + mid) / 2;
}
}
if (vva[n - 1] == '1') mid++;
return mid;
}
int main() {
int N;
int cases = 0;
while (cin >> N && N != 0) {
cases++;
string tmp;
for (int i = 0; i < N; i++) {
cin >> tmp;
}
char terminal_node[150];
cin.ignore(1);
for (int i = 1; i <= (int)pow(2, N); i++) {
terminal_node[i] = getchar();
}
int M; cin >> M;
printf("S-Tree #%d:\n", cases);
for (int i = 0; i < M; i++) {
cin.ignore(1);
char vva[10];
for (int i = 0; i < N; i++) {
vva[i] = getchar();
}
int index = s_tree_function(vva, N);
cout << terminal_node[index];
}
cout << endl << endl;
}
return 0;
}