ababcd letsgogogo nowletsgogogoletsgogogoandrunrunrun
6 9 24
题意:给出一个长度不超过200的字符串,把这个字符串按照一定规则压缩,即可以把几个连续的相同子串压缩成一个串,例如可以把letsgogogo压缩为lets3(go),压缩后的子串如果还可以继续压缩,则可以继续压缩,如可以将nowletsgogogoletsgogogoandrunrunrun压缩为now2(lets3(go))and3(run)。问经过压缩后这个字符串的最短长度是多少。
分析: 区间DP,dp[i][j]表示从i到j的字符串表示的最短长度。
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j])。注意如果是数字,要用数字的位数表示增加的个数,而不是单纯的增加1.
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 210; #define INF 0x3fffffff char str[N]; int n, dp[N][N]; int digit_cnt(int x) { int a = 0; while(x) { a++; x /= 10; } return a; } bool check(int l, int r, int len) { if((r - l + 1) % len) return false; for(int i = l; i < l + len; i++) { for(int j = i + len; j <= r; j += len) if(str[i] != str[j]) return false; } return true; } int get_ans() { int i, j, k; n = strlen(str+1); for(i = 1; i <= n; i++) dp[i][i] = 1; for(i = n - 1; i >= 1; i--) { for(j = i + 1; j <= n; j++) { dp[i][j] = INF; for(k = i; k < j; k++) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]); for(int len = 1; len <= j-i+1; len++) { if(check(i, j, len)) { dp[i][j] = min(dp[i][j], dp[i][i+len-1] + 2 + digit_cnt((j - i + 1) / len)); } } } } return dp[1][n]; } int main() { while(~scanf("%s", str+1)) { printf("%d\n", get_ans()); } return 0; }
NYOJ 1067 Compress String(区间dp),布布扣,bubuko.com
NYOJ 1067 Compress String(区间dp)
原文:http://blog.csdn.net/lyhvoyage/article/details/38455687