思路:
相信大家都很容易想到, 根據字串的長度, 求出所有約數, 然後按照約數的順序來檢驗 . 但是檢驗的策略非常重要, 最重要的兩點就是:
(1)對每個不同長度週期的字串, 最多隻判斷一次.
(2)如果長度為n的字串在原串的週期檢驗中不成立, 則長度為n的約數的字串也不會成立 .
根據上述的結論, 我們可以大概感覺到, 我們不僅要求約數, 還要求約數的約數( 依次遞迴 ) , 而約數的約數本身又是原數的約數 , 至此, 可以斷定使用多叉數結構(有向圖)來進行約數儲存( 我把它稱為約數樹 ).
完全約數樹: 如果根結點的所有約數都是根結點的下屬結點(無論直接或間接), 則該樹為完全約數樹.
在貼**之前, 我要對約數樹的理論結構做出宣告:
(1) 描述整個問題域的約數樹是一棵完全約數樹, 但其所有子樹都不一定是完全約數樹( 這樣可以避免約數重複而導致的週期判斷重複 ).
(2) 從樹根開始, 先序遍歷約數樹進行週期判斷, 如果某結點判斷失敗, 根據策略2, 則其所有子樹結點都將失敗, 不必再檢驗.
以24為例, 給出如下約數樹:
/*約數樹 : 子結點必然是根結點的約數, 但反之不成立*/
struct edgee[maxn]; // ...所有邊的集合
struct cnodev[maxn]; // ...所有點的集合
int nedgecount = 0; // ...當前已經使用的邊的總量
int strlen; // ...原字串總長度
int minlen = maxn; // ...當前已知的最小正週期
char ss[maxn]; // ...原字串
// 新增一條從v[root]指向v[subroot] 的邊
// 複雜度: o(1)
inline void addedge( int root, int subroot )
// 建立約數樹
// 複雜度: o(?)
void buildtree( int root )
if( !v[i].isbuilt )
} }}// 匹配原串ss[0 ... length-1] 中是否存在長度為partlen的週期串
// 複雜度: o(length)
bool match( int length, int partlen )
} return true;
}// 匹配 ss[ 0 ... root-1] 中的最小週期串
// 複雜度: o( root的約數總數 )
void dfs_match( int root )
int main(int argc, char** argv)
最後說兩句:以約數樹為基的檢驗策略似乎沒有從根源上減低時間複雜度, 甚至因為建樹而耗損了一些額外的時間, 但其的確大大減低了原複雜度的係數, 整個演算法從根本上來說, 只是一種可行性剪枝, 但本人最後沒有辦法算出建樹的複雜度,所以無法準確推敲.
藍橋杯 ADV 150演算法提高 週期字串
字串 abcabcabcabc 週期為3,因為它是由4個迴圈 abc 組成的。它同樣是以6為週期 兩個重複的 abcabc 和以12為週期 乙個迴圈 abcabcabcabc 右右現在想給他的朋友大灰狼轉述媽媽講的故事,請幫他寫乙個程式,可以測定乙個字串的最小週期。輸入格式 乙個最大長度為100的無...
藍橋杯 演算法提高 字串壓縮
問題描述 編寫乙個程式,輸入乙個字串,然後採用如下的規則對該字串當中的每乙個字元進行壓縮 1 如果該字元是空格,則保留該字元 2 如果該字元是第一次出現或第三次出現或第六次出現,則保留該字元 3 否則,刪除該字元。例如,若使用者輸入 occurrence 經過壓縮後,字元c的第二次出現被刪除,第一和...
藍橋杯 週期字串 字串處理
演算法提高 週期字串 時間限制 1.0s 記憶體限制 256.0mb 問題描述 右右喜歡聽故事,但是右右的媽媽總是講一些 從前有座山,山里有座廟,廟裡有個老和尚給小和尚講故事,講的什麼呢?從前有座山 這樣迴圈的故事來搪塞右右。我們定義,如果乙個字串是以乙個或者乙個以上的長度為k的重複字串所連線成的,...