UVA 1351 - String Compression(区间DP)

来源:互联网 发布:centos7网络配置 rules 编辑:程序博客网 时间:2024/04/29 09:01

Run Length Encoding(RLE) is a simple form of compression. RLE consists of the process for searching for a repeated runs of a single character in a string to be compressed, and replacing them by a single instance of the character and a run count. For example, a string abcccddddddefgggggggggghijk is encoded into a stringab3c6def10ghijk by RLE.

A new compression method similar to RLE is devised and the rule of the method is as follows: if a substringS 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 `(' and `)'). For example, the length of 123(abc) is 8. It is also possible to nest compression, so the substring S may itself be a compressed string. For example,nowletsgogogoletsgogogo could be compressed as a now2(lets3(go)), and nowletsgogogoletsgogogoandrunrunrun could be compressed as now2(lets3(go))and3(run).

Write a program that, for a given string, gives a shortest compressed string using the compression rules as described above.

Input 

Your program is to read from standard input. The input consists of T test cases. The number of test cases Tis given in the first line of the input. Each test case consists of a single line containing one string of no more than 200 characters drawn from a lower case alphabet. The length of shortest input string is 1.

Output 

Your program is to write to standard output. Print exactly one line for each test case. For each test case, print the length of the shortest compressed string.

The following shows sample input and output for four test cases.

Sample Input 

4 ababcd letsgogogo nowletsgogogoletsgogogo nowletsgogogoletsgogogoandrunrunrun

Sample Output 

6 9 15 24

题意:给你一个字符串,连续相同字符可以表示成:个数(字符串),比如gogogo可以表示为3(go)。问怎么去表示使得字符串最短。

思路:一开始题意没注意,比如第三组样例是可以表示为now2(let3(go))的。

区间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 <stdio.h>#include <string.h>#define INF 0x3f3f3f3f#define min(a,b) ((a)<(b)?(a):(b))const int N = 205;int T, dp[N][N], n;char str[N];int digcount(int x) {int ans = 0;while (x) {x /= 10;ans++;}return ans;}bool judge(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 solve() {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 (judge(i, j, len)) {dp[i][j] = min(dp[i][j], dp[i][i + len - 1] + 2 + digcount((j - i + 1) / len));}}}}return dp[1][n];}int main() {scanf("%d", &T);while (T--) {scanf("%s", str + 1);printf("%d\n", solve());}return 0;}


2 0