範例程式碼已於 UVA
、瘋狂程設(CPE)
、ZeroJudge
上皆測試通過。
題意
電子滾動顯示器(Electric scrolling signs) 有固定的顯示字元數,每次滾動時會將最左邊的字元移出,並在最右邊添加一個新字元,我們的目標是通過最少的字元滾動數來顯示一系列指定的單字。
舉例來說,假設顯示器有 3 3 3 個字元位置,訊息中包含 3 3 3 個單字 [ CAT , ATE , TED ] [\textit{CAT}, \textit{ATE}, \textit{TED}] [ CAT , ATE , TED ] ,則需要滾動 5 5 5 個字元才能顯示所有單字。
顯示第一個單字 CAT \textit{CAT} CAT 需要滾動 3 3 3 個字元: C , A , T \textit{C}, \textit{A}, \textit{T} C , A , T 。
接著顯示第二個單字 ATE \textit{ATE} ATE ,可以利用第一個單字中的最後兩個字元 A \textit{A} A 和 T \textit{T} T ,只需要再滾動 1 1 1 個字元:E \textit{E} E 。
最後顯示第三個單字 TED \textit{TED} TED ,可以利用第二個單字中的最後兩個字元 T \textit{T} T 和 E \textit{E} E ,只需要再滾動 1 1 1 個字元:D \textit{D} D 。
給定能夠顯示的字元數 n = k n = k n = k 和 m = w m = w m = w 個長度為 n n n 的單字,請求出 最少需要滾動的字元數 。
約束條件
1 ≤ n ≤ 100 1 \leq n \leq 100 1 ≤ n ≤ 100
1 ≤ m ≤ 100 1 \leq m \leq 100 1 ≤ m ≤ 100
思路:字串(String)
由於可以和前一個單字重複使用部分字元,我們可以透過比較相鄰的兩個單字,找到可以共用字元的位置,從而減少需要滾動的字元數量。
初始化答案 a n s = n ∗ m ans = n * m an s = n ∗ m ,若每個單字都需要滾動 n n n 個字元,則總共需要滾動 n ∗ m n * m n ∗ m 個字元。
對於相鄰的兩個單字 w a wa w a 和 w b wb w b ,我們透過檢查每個 w a wa w a 的後綴和 w b wb w b 的前綴,找到它們的最大重疊部分,並減去不必要的滾動字元數,即 w a [ i : ] = w b [ : n − i ] wa[i:] = wb[:n-i] w a [ i : ] = w b [ : n − i ] ,其中 n − i n - i n − i 為重疊部分的長度。
複雜度分析
時間複雜度:O ( m ⋅ n 2 ) \mathcal{O}(m \cdot n^2) O ( m ⋅ n 2 )
每個測試案例中,我們需要比較 m − 1 m-1 m − 1 對相鄰單字的各種重疊情況。每個單字長度為 n n n ,需要從長度為 n n n 開始檢查最大重疊部分,總共檢查 n n n 種長度。
空間複雜度:O ( m ⋅ n ) \mathcal{O}(m \cdot n) O ( m ⋅ n ) ,主要用於儲存單字列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 T = int (input ()) for _ in range (1 , T+1 ): n, m = map (int , input ().split()) words = [input () for _ in range (m)] ans = n * m for i in range (m-1 ): wa, wb = words[i], words[i+1 ] for i in range (n): if wa[i:] == wb[:n-i]: ans -= n - i break print (ans)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <bits/stdc++.h> using namespace std;#define endl '\n' int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cout.tie (nullptr ); int t, n, m, ans; cin >> t; while (t--) { ans = 0 ; cin >> n >> m; vector<string> words (m) ; for (int i=0 ; i<m; i++){ cin >> words[i]; } ans = n * m; for (int i=0 ; i<m-1 ; i++){ for (int j=0 ; j<n; j++){ if (words[i].substr (j) == words[i+1 ].substr (0 , n-j)){ ans -= n - j; break ; } } } cout << ans << endl; } }
寫在最後
Cover photo is remixed from @Tekeli_liw3 , thanks for their work!