https://vjudge.net/problem/UVA-1630
题意:
给出一个由大写字母组成的长度为n的串,折叠成一个尽量短的串。例如:AAAAAAAAABABABCCD折叠成9(A)3(AB)CCD。
思路:
参考自http://blog.csdn.net/a197p/article/details/48701227。自己实在是没什么思路,也是看了很久才搞明白。
DP[i][j]表示的是 i~j 压缩后的长度。
fold[i][j]存储 i~j 压缩后的状态。
1 #include<iostream> 2 #include<string> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const int INF = 0x3f3f3f3f; 8 string str; 9 int DP[110][110]; 10 string fold[110][110]; 11 12 int judge(int l, int r) 13 { 14 //这里判重用的就是枚举 15 for (int i = 1; i <= (r - l + 1) / 2; i++) 16 { 17 if ((r - l + 1) % i) continue; 18 bool flag = true; 19 for (int j = l; j + i <= r; j++) 20 { 21 if (str[j] != str[j + i]) 22 { 23 flag = false; 24 break; 25 } 26 } 27 if (flag) return i; 28 } 29 return false; 30 } 31 32 int fun(int l, int r) 33 { 34 if (DP[l][r] != -1) return DP[l][r]; 35 36 if (l == r) 37 { 38 DP[l][r] = 1; 39 fold[l][r] = str[l]; 40 return 1; 41 } 42 int k; 43 int re = INF; 44 //找到一个k,两段折叠后连接达到最短 45 for (int i = l; i < r; i++) 46 { 47 int tmp = fun(l, i) + fun(i + 1, r); 48 if (tmp < re) { k = i; re = tmp; } 49 } 50 fold[l][r] = fold[l][k] + fold[k + 1][r]; 51 int len = judge(l, r); 52 //对重复串的压缩 53 if (len) 54 { 55 bool test = true; 56 for (int i = l; i <= r; i++) 57 { 58 if (str[i] == '(' || str[i] == ')') test = false; //不要把括号作为压缩对象 59 } 60 char t[10]; 61 sprintf(t, "%d", (r - l + 1) / len); 62 string newstr = t + string("(") + fold[l][l + len - 1] + string(")"); 63 if (test && newstr.size()<re) 64 { 65 re = newstr.size(); 66 fold[l][r] = newstr; 67 } 68 } 69 DP[l][r] = re; 70 return re; 71 } 72 73 int main() 74 { 75 //freopen("D:\txt.txt", "r", stdin); 76 while (cin >> str) 77 { 78 int R = str.size() - 1; 79 memset(DP, -1, sizeof(DP)); 80 fun(0, R); 81 cout << fold[0][R] << endl; 82 } 83 return 0; 84 }