题目大意:
给你一个字符串,让你把它压缩,比如gogogo可以压缩成3(go),letsgogogoletsgogogo可以压缩成2(lets3(go)),然后问你压缩后的最短长度。
解题思路:
区间DP。
一开始我以为是个基础的DP。没想到在第二个样例过不去,才发现这不是个基础的DP,也不是...这应该算是基础的区间DP吧。
首先设dp[i][j]表示从i到j这个区间内的字符串能压缩的最短长度。
那么状态转移方程就是
dp[i][j] = min(dp[i][k] + dp[k+1][j], dp[i][i+a] + 2 + len(a));
q其中k是[i,j]区间内的任意整数点,a是将字符串i到j的子串缩成长度为a的字符串的长度。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 205; const int INF = 0x3f3f3f3f; char str[maxn]; int dp[maxn][maxn]; int check(int be, int en, int k) { if ((en - be + 1) % k) return 0; for (int i = be + k; i <= en; i += k) for (int j = 0; j < k; ++j) if (str[i + j] != str[be + j]) return 0; return (en - be + 1) / k; } int getNum(int x) { if (x >= 0 && x <= 9) return 1; else if (x >= 10 && x <= 99) return 2; else return 3; } int main() { int t; scanf("%d", &t); while (t--) { scanf(" %s", str); int tmp, len = strlen(str); for (int i = 0; i < len; ++i) dp[i][i] = 1; for (int i = 0; i < len; ++i) { for (int j = i - 1; j >= 0; --j) { dp[j][i] = INF; for (int k = j; k < i; ++k) dp[j][i] = min(dp[j][i], dp[j][k] + dp[k+1][i]); for (int k = 1; k <= (i - j + 1) / 2; ++k) { int tmp = check(j, i, k); if (tmp) dp[j][i] = min(dp[j][i], dp[j][j + k - 1] + 2 + getNum(tmp)); } } } printf("%d ", dp[0][len-1]); } return 0; }