1. 程式人生 > 其它 >演算法競賽入門經典 7-5 困難的串 UVa129(回溯法)

演算法競賽入門經典 7-5 困難的串 UVa129(回溯法)

題意:將一個包含兩個相鄰的重複子串的字串,稱為“容易的串”,其他為“困難的串”。 輸入正整數n和l,輸出由前l個大寫字母組成的,字典序第n小的困難的串。

提交地址:UVA129 困難的串 Krypton Factor - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

一種容易想到的做法是每次在末尾新增字元,然後列舉所有長度為偶數的子串判斷是否合法。

顯然,這樣做會造成大量的重複計算。對於一個新增的字元,我們只需要考慮以它為末尾的子串,也即當前字串的字尾,這樣即可不重不漏地遍歷所有列舉到的字串。 當一個串成為“簡單的串”後,往後再新增字元也不會成為困難的串,此時回溯即可。

 1
#include <bits/stdc++.h> 2 3 using namespace std; 4 int n, l, cnt; 5 string str; 6 7 void print(string str) { 8 int len = str.length(); 9 for (int i = 0; i < len; i++) { 10 printf("%c", str[i]); 11 if (i && (i + 1) % 64 == 0) printf("\n"); 12 else if (i && (i + 1
) % 4 == 0 && i != len - 1) printf(" "); 13 } 14 if (len % 64) printf("\n"); 15 printf("%d\n", len); 16 } 17 18 bool check(string str) { 19 int len = str.length(); 20 for (int k = 1; k * 2 <= len; k++) { 21 string s1 = str.substr(len - k, k); 22 string s2 = str.substr(len - k * 2
, k); 23 if (s1 == s2) return true; 24 } 25 return false; 26 } 27 28 bool dfs(int len) { 29 //getchar(); 30 if (!check(str)) cnt++; 31 else return false; 32 if (cnt == n) { 33 print(str); 34 return true; 35 } 36 for (char c = 'A'; c - 'A' < l; c++) { 37 str.push_back(c); 38 if (!dfs(len+1)) str.pop_back(); 39 else return true; 40 } 41 return false; 42 } 43 44 int main() { 45 while (cin >> n >> l && n) { 46 str = ""; 47 cnt = 0; 48 for (char c = 'A'; c - 'A' < l; c++) { 49 str.push_back(c); 50 if (!dfs(1)) str.pop_back(); 51 else break; 52 } 53 } 54 return 0; 55 }