# APCS實作題2018年10月第3題:DF-expression > 日期:2024年8月20日 > 作者:王一哲 > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=f637) ## 題目 ### 問題描述 DF-express (深度優先圖像表示式) 是一個具有高度資料壓縮能力的四元樹表示法。雖然主要為二階黑白圖片所設計,但是透過位元平面 (bit-plane) 或是 3D 表示法,亦可用來壓縮灰階圖片。 本題中所處理的圖片為二階的黑白圖片,也就是每個像素非黑即白,沒有中間的灰色。圖片大小為 $n \times n$,$n$ 是 $2$ 的冪次,也就是存在某個非負整數 $k$ 使得 $n = 2^k$。 一個 $n \times n$ 的黑白影像可以用下列遞迴方式編碼: 如果每一格像素都是白色,我們用 $0$ 來表示;如果每一格像素都是黑色,我們用 $1$ 來表示;否則,並非每一格像素都同色,先將影像均等劃分為四個邊長為 $n/2$ 的小正方形後,然後表示如下:先寫下 $2$,之後依續接上左上、右上、左下、右下四塊的編碼。 一個壓縮後的影像會表示成一個由 $0$、$1$、$2$ 組成的字串 $S$。在這個問題中,根據字串 $S$ 以及影像尺寸 $n$,請計算原始影像中有多少個像素是 $1$。 <br /> ### 輸入說明 測試資料有兩行,第一行是影像的 DF-expression $S$,是由連續的 $0$、$1$、$2$ 組成的字串,字串長度小於 $1,100,000$。第二行為正整數 $n$,$1 \leq n \leq 1024$,代表影像的大小為 $n \times n$,其中 $n$ 必為 $2$ 的冪次。 <br /> ### 輸出格式 請輸出該影像中有多少像素是 $1$。 <br /> ### 範例輸入1 ``` 2200101020110 4 ``` ### 範例輸出1 ``` 7 ``` ### 範例輸入2 ``` 2020020100010 8 ``` ### 範例輸出2 ``` 17 ``` <br /><br /> ## Python 程式碼 費時最久約為 1 s,使用記憶體最多約為 6.9 MB,通過測試。 ```python= S = input() # 讀取字串 S n = int(input()) # 讀取維度 n k = 0 # 平分 k 次 ans = 0 # 1 的數量 count = [0] # 每一層已檢查過的格子象限數量,加到 4 時跳回上一層 for c in S: # 依序由 S 取出字元 c while count[-1] == 4: # 如果 count 最後一位等於 4 繼續執行 count.pop() # 移除最後一位 k -= 1 # k 減 1,回上一層 n *= 2 # n 乘以 2,回上一層 count[-1] += 1 # 上一層檢查過的象限數量加 1 if c == '2': # 如果 c 是 2 n //= 2 # n 除以 2 k += 1 # k 加 1,向下一層 count.append(0) # count 加一層 elif c == '1': # 如果 c 是 1 ans += n*n # 更新 1 的數量,加上 n*n count[-1] += 1 # 已檢查的象限數量加 1 elif c == '0': # 如果 c 是 0 count[-1] += 1 # 已檢查的象限數量加 1 #print("c = {:s}, k = {:d}, n = {:d}, ans = {:d}, count = {:}".format(c, k, n, ans, count)) print(ans) # 印出答案 ``` <br /><br /> ## C++ 程式碼 費時最久約為 12 ms,使用記憶體最多約為 3.5 MB,通過測試。 ```cpp= #include <iostream> #include <string> #include <vector> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); // 加速 string S; cin >> S; // 讀取字串 S int n; cin >> n; // 讀取維度 n int k = 0, ans = 0; // 平分 k 次,1 的數量 vector<int> count = {0}; // 每一層已檢查過的格子象限數量,加到 4 時跳回上一層 for(char c : S) { // 依序由 S 取出字元 c while(count.back() == 4) { // 如果 count 最後一位等於 4 繼續執行 count.pop_back(); // 移除最後一位 k--; // k 減 1,回上一層 n *= 2; // n 乘以 2,回上一層 count[count.size()-1]++; // 上一層檢查過的象限數量加 1 } if (c == '2') { // 如果 c 是 2 n /= 2; // n 除以 2 k++; // k 加 1,向下一層 count.push_back(0); // count 加一層 } else if (c == '1') { // 如果 c 是 1 ans += n*n; // 更新 1 的數量,加上 n*n count[count.size()-1]++; // 已檢查的象限數量加 1 } else if (c == '0') { // 如果 c 是 0 count[count.size()-1]++; // 已檢查的象限數量加 1 } } cout << ans << "\n"; // 印出答案 return 0; } ``` <br /><br /> --- ###### tags:`APCS`、`Python`、`C++`