標籤:dp
Compress String時間限制:2000 ms | 記憶體限制:65535 KB難度:3
-
描述
-
One day,a beautiful girl ask LYH to help her complete a complicated task—using a new compression method similar to Run Length Encoding(RLE) compress a string.Though the task is difficult, LYH is glad to help her.The compress rules of the new method is as follows: if a substring S is repeated k times, replace k copies of S by k(S). For example, letsgogogo is compressed into lets3(go). The length of letsgogogo is 10, and the length of lets3(go) is 9. In general, the length of k(S) is (number of digits in k ) + (length of S) + 2. For example, the length of 123(abc) is 8. It is also possible that substring S is a compressed string. For example nowletsgogogoletsgogogoandrunrunrun could be compressed as now2(lets3(go))and3(run).In order to make the girl happy, LYH solved the task in a short time. Can you solve it?
-
輸入
-
Thera are multiple test cases.
Each test case contains a string, the length of the string is no more than 200, all the character is lower case alphabet.
-
輸出
-
For each test case, print the length of the shortest compressed string.
-
範例輸入
-
ababcd letsgogogonowletsgogogoletsgogogoandrunrunrun
-
範例輸出
-
6924
-
題意:給出一個長度不超過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])。
然後去判斷當前子串能不能壓縮,即是否由重複字串組成,判斷時只需暴力枚舉重複長度,去判斷即可。
如果當前子串可以壓縮,則dp[i][j] = min(dp[i][j], dp[i][i + len - 1] + 2 + digcount((j - i + 1) / len));,
注意如果是數字,要用數位位元表示增加的個數,而不是單純的增加1.
-
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N = 210;#define INF 0x3fffffffchar 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;}