題目大意:
給你一個字符串,讓你把它壓縮,比如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\n", dp[0][len-1]);
}
return 0;
}