bzoj 1068: [SCOI2007]压缩1068: [SCOI2007]压缩

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/83342455

1068: [SCOI2007]压缩1068: [SCOI2007]压缩

给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小
写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没
有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程
另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。

输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
长度不超过50.

思路。
我们可以用 f[i][j][0/1]来表示i 到 j 之间,有没有用放 M。
一开始。
f[i][j][0] = j - i + 1;
f[i][j][1] = j - i + 1;
接着状态转移。
f[i][j][0] = min(f[i][j][0],f[i][k][0] + j - k),
这个是不放M 的。
f[i][j][1] = min(f[i][j][1],min(f[i][k][1],f[i][k][0]) + min(f[k+1][j][1],f[k+1][j][0]) + 1);
这个是在第k个位置放了M。
还有一个放 R 的。
f[i][j][0] = f[i][(i+j)/2][0] + 1
这个我们要判断一下,i 到j 之间是不是偶数,还有是不是重复的。

#include<bits/stdc++.h>
using namespace std;

char s[100];
int f[100][100][2];
bool check(int x, int y){
	if ((y-x+1) & 1) return 0;
	int mid = (x + y) / 2;
	for (int i = 1; i <= mid - x + 1; i++)
		if (s[x + i - 1] != s[mid + i]) return 0;
	return 1;
}
int main(){
	int len;
	scanf("%s",s+1);
	len = strlen(s+1);
	for (int i = len; i > 0; i--){
		for (int j = i; j <= len; j++){
			f[i][j][0] = j - i + 1;
			f[i][j][1] = j - i + 1;
			for (int k = i; k < j; k++)
				f[i][j][0] = min(f[i][j][0],f[i][k][0] + j - k);
			for (int k = i; k < j; k++)
				f[i][j][1] = min(f[i][j][1],min(f[i][k][1],f[i][k][0]) + min(f[k+1][j][1],f[k+1][j][0]) + 1);
			if (check(i,j)) f[i][j][0] = f[i][(i+j)/2][0] + 1;

		}
	}
	printf("%d\n",min(f[1][len][0],f[1][len][1]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/83342455
今日推荐