您的位置:首页 > 其它

UVALive 3363 String Compression

2013-08-05 15:59 204 查看
题目大意:给你一种压缩字符串的方式,可以将相同的连续的重复字串表示成k(s)的形式,比如“nowletsgogogoletsgogogoandrunrunrun”,就可以压缩为“ now2(lets3(go))and3(run)”,给你一个字符串,问你用这种方法压缩,最少的字符个数是多少?

思路:用d[ i ][ j ] 来表示第i个字符到第j个字符的最小长度,那么d[ i ][ j ] = min(min(d[ i ][ k ]+d[ k + 1][ j ]),min(d[ i ][ i + dis - 1 ] + digs + 2)),其中第一部分为枚举将i~j 这部分进行拆分,而光这样转移是不够的,因为枚举的两个部分长度都是小于总长度(j-i+1)的,还有一种情况就是整段都可以是由一个字串重复组成,所以第二部分是关键,dis是指枚举的最小的重复字串的长度,当然dis满足(j - i
+1)%dis == 0 && i~j这一段可以是i~i+dis-1 这一段重复产生的,digs是指前面那个数字的长度,10以下是1,10~99是2,100~999是3,而2指的是两边的括号。

好吧,我承认我看到这道题的时候完全没有思路,我先开始只想到开一维的d[ i ] 来表示状态,感觉状态转移太复杂了,也就没有继续往下做了,想想变成d[ i ][ j ] 好像也很复杂的样子。。 后来去搜题解,找了半天找不到,后来有幸找到了一份代码,研究了一下,思路、代码很快就懂了,之后想想也不是很难,可自己就是想不到啊,而且每次都不会继续深入下去,感觉太烦就不往下想了。自己想到,和看题解看会差距是很大的!火候还差很多啊,继续多想,多练吧。。 还有一点,不到迫不得已,不搜题解!

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 222;

char str[MAXN];

int d[MAXN][MAXN];

int nums[MAXN];

int check(int l,int r,int dis)
{
for(int i = 0;i<dis;i++)
{
for(int j = l+i;j<=r;j += dis)
{
if(str[l+i]!=str[j]) return 0;
}
}
return 1;
}

void dp(int l,int r)
{
int len = r - l + 1 ;
int ret = len ;
for(int i = l;i<r;i++) ret = min(ret,d[l][i]+d[i+1][r]);
for(int dis = 1;dis<=len/2;dis++)
{
if(len%dis==0)
{
if(check(l,r,dis))
{
ret = min(ret,nums[len/dis]+d[l][l+dis-1]+2);
}
}
}
d[l][r] = ret;
}

void init()
{
for(int i = 0;i<10;i++)
nums[i] = 1;
for(int i = 10;i<100;i++)
nums[i] = 2;
for(int i = 100;i<MAXN;i++)
nums[i] = 3;
}

int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",str);
int len = strlen(str);
for(int dis = 1;dis<=len;dis++)
{
for(int i = 0;i<len;i++)
{
int j = i+dis-1;
if(j>len) break;
dp(i,j);
}
}
printf("%d\n",d[0][len-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: