uva 1351 - String Compression(dp)

题目链接:uva 1351 - String Compression


题目大意:给出一个字符串,如果相邻的m个连续子串相等的为s0话,可以将该段表示为m(s0),问说最短需要几个字符可以表示所给字符串。


解题思路:首先要注意(1)m可能是两位数三位数等等;(2)左右括号各算一个字符;(3)s0可以为简化过的字符串,例如s0中包含了一个k(s1)。

然后是dp[i][j]表示的是从i到j的最少字符数,若不考虑i~j这段字符串可以被简化,那么dp[i][j] = min{ dp[i][k] + dp[k+1][j] },但是i~j字符串可以被简化的情况也要考虑,枚举s0的长度,然后去进行判断,是否满足题目要求,满足要求的要维护dp[i][j]最小值dp[i][j] = min(dp[i][j], dp[i][i+k-1] + 2 + catnum((j-i+1)/k));


#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int N = 205;
const int INF = 0x3f3f3f3f;

int dp[N][N];
char str[N];

bool judge(int l, int r, int k) {
	if ((r-l+1)%k) return false;

	for (int i = 0; i < k; i++) {
		for (int j = l+i+k; j <= r; j += k) if (str[l+i] != str[j])
			return false;
	}		
	return true;
}

int catnum(int x) {
	int ans = 0;
	while (x) {
		ans++;
		x /= 10;
	}
	return ans;
}

int solve () {

	scanf("%s", str+1);
	int n = strlen(str+1);

	memset(dp, INF, sizeof(dp));
	for (int i = 0; i <= n; i++) dp[i][i] = 1;

	for (int i = n; i; i--) {
		for (int j = i; j <= n; j++) {
			for (int k = i; k < j; k++) 
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);

			int t = j - i + 1;
			for (int k = 1; k < t; k++) if (judge(i, j, k)) {
				dp[i][j] = min(dp[i][j], dp[i][i+k-1] + 2 + catnum(t/k));
			}
		}
	}
	return dp[1][n];
}

int main () {
	int cas;
	scanf("%d", &cas);
	while (cas--) {
		printf("%d\n", solve());	
	}
	return 0;
}



你可能感兴趣的:(uva 1351 - String Compression(dp))