UVA297:Quadtrees(四分樹)
題目描述
四象樹是每個內結點均有4個子結點的特殊四叉樹,它可用於描述平面上黑白圖像。平面上的黑白圖像是32行×32列的正方形,每個格子稱為1個象素,是最小的圖像單位。正方形圖像可分成四個相等的小正方形,可按直角坐標系四個象限的順序分別編號1,2,3,4,分別對應於四象樹的四個子結點。這樣,32行×32列的圖像就對應於一棵深度為6的完全四叉樹,最底層的每個葉結點正好對應於一個象素。但我們可以壓縮四象樹的結點數量。
當圖像上某個區域為全白或者全黑時,可把該區域在四象樹上對應的結點描述為全白(用小寫字母e表示)或者全黑(用小寫字母f表示),並且對這樣的結點不再擴展子結點,因為再擴展出的子樹上每個結點都是相同的顏色。
只有當圖像上某個區域為“雜色”時,才繼續劃分成四個子區域(在四象樹上對應的結點用小寫字母p表示),然後“純”色的子區域也不再擴展,並繼續擴展“雜”色子區域。例如,下圖左、中兩個圖像可分別用它們下邊的四象樹描述。
我們感興趣的問題是:當兩個大小均為32*32的黑白圖像疊加後,合成的新圖像是什麽樣子。合成的規則是:當一個圖像上某個區域為全黑時,新圖像的這個區域即為全黑;當一個圖像上某個區域為全白時,新圖像的這個區域的顏色是另加一個圖像上這個區域的顏色。上圖準確地示例了本合成的規則。
我們給出兩個圖像對應四象樹的先序遍歷順序,求合成後的圖像中,黑色象素點的數量。
輸入
多組測試數據,第1行一個整數T,表示測試數據的組數,每組數據的格式為:
第1行:一個字符串,描述第1棵四象樹的先序序列
第2行:一個字符串,描述第2棵四旬樹的先序序列
輸出
對每組數據,在單獨一行上輸出一個整數,表示合成後的圖像上黑色象素的數量,格式如輸出樣例所示:
樣例輸入
3
ppeeefpffeefe
pefepeefe
peeef
peefe
peeef
peepefefe
樣例輸出
There are 640 black pixels.
There are 512 black pixels.
There are 384 black pixels.
我直接把BZOJ的翻譯粘過來了(逃
思路1:數據量很小。我第一次寫時直接模擬了兩棵四叉樹的建樹與搜索,然後捎帶著把最後的黑色個數算出來了。其中黑色結點的值跟它的深度有關,寫一寫就能找到規律。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <cmath> 5 using namespace std; 6 7 struct node 8 { 9 char c; 10 node *ptr[4]; 11 node(){for (int i = 0; i < 4; i++) ptr[i] = NULL;} 12 }; 13 14 node *root1, *root2; 15 16 int sum, cnt;//sum是最終結果,cnt是記錄字符串走到哪個位置了 17 18 void release(node *root)//釋放 19 { 20 if (!root) return; 21 for (int i = 0; i < 4; i++) 22 release(root->ptr[i]); 23 delete root; 24 } 25 26 void build(string cur, node *&root)//建樹,記得root要加地址符 27 { 28 root = new node(); 29 root->c = cur[cnt++]; 30 if (root->c == ‘p‘) 31 for (int i = 0; i < 4; ++i) 32 { 33 root->ptr[i] = new node(); 34 build(cur, root->ptr[i]); 35 } 36 } 37 38 void dfs(node *root1, node *root2, int depth) 39 { 40 //大概分了三種情況討論 41 if (root1->c == ‘f‘ || root2->c == ‘f‘)//有一個是黑 42 { 43 sum += pow(4,6-depth);//數學可推…… 44 return; 45 } 46 else if (root1->c == ‘e‘ && root2->c == ‘e‘)//全是白 47 return; 48 //對於‘p‘的點深搜 49 bool flag1 = root1->c==‘p‘, flag2 = root2->c==‘p‘; 50 node *x = root1, *y = root2; 51 for (int i = 0; i < 4; i++) 52 { 53 if (flag1) x = root1->ptr[i]; 54 if (flag2) y = root2->ptr[i]; 55 dfs(x, y, depth+1); 56 } 57 } 58 59 int main() 60 { 61 int test; 62 scanf("%d", &test); 63 64 while (test--) 65 { 66 sum = 0; 67 string s,t; 68 cin >> s >> t; 69 cnt = 0, build(s, root1); 70 cnt = 0, build(t, root2); 71 72 dfs(root1, root2, 1); 73 74 printf("There are %d black pixels.\n", sum); 75 76 release(root1),release(root2); 77 } 78 79 return 0; 80 }
思路2:書上代碼思路是在32*32的正方形裏面塗色然後查找,貌似跟樹也沒什麽關系了……書中的註釋已經很明白了,見代碼。(PS:UVA有毒)
1 #include <cstdio> 2 #include <cstring> 3 4 const int len = 32; 5 const int maxn = 1024 + 10; 6 //下面這個char數組和int變量定義順序變一下UVA居然會WA啊! 7 //我從未見過如此厚顏無恥之OJ 8 char s[maxn]; 9 int buf[len][len], cnt; 10 11 //把字符串s[p..]導出到以(r,c)為左上角,邊長為w的緩沖區中 12 //2 1 13 //3 4 14 void draw(const char* s, int& p, int r, int c, int w) 15 { 16 char ch = s[p++]; 17 if (ch == ‘p‘) 18 { 19 draw(s, p, r , c+w/2, w/2);//1 20 draw(s, p, r , c , w/2);//2 21 draw(s, p, r+w/2, c , w/2);//3 22 draw(s, p, r+w/2, c+w/2, w/2);//4 23 } 24 else if (ch == ‘f‘) 25 for (int i = r; i < r+w; i++) 26 for (int j = c; j < c+w; j++) 27 if (buf[i][j] == 0) 28 buf[i][j] = 1,cnt++; 29 } 30 31 int main() 32 { 33 int t; 34 scanf("%d", &t); 35 36 while (t--) 37 { 38 memset(buf, 0, sizeof(buf)); 39 cnt = 0; 40 for (int i = 0; i < 2; i++) 41 { 42 scanf("%s",s); 43 int p = 0; 44 draw(s, p, 0, 0, len); 45 } 46 47 printf("There are %d black pixels.\n", cnt); 48 49 } 50 51 return 0; 52 }
UVA297:Quadtrees(四分樹)