其他分享
首页 > 其他分享> > [POJ 2176] Folding

[POJ 2176] Folding

作者:互联网

问题描述

Bill is trying to compactly represent sequences of capital alphabetic characters from 'A' to 'Z' by folding repeating subsequences inside them. For example, one way to represent a sequence AAAAAAAAAABABABCCD is 10(A)2(BA)B2(C)D. He formally defines folded sequences of characters along with the unfolding transformation for them in the following way:

According to this definition it is easy to unfold any given folded sequence. However, Bill is much more interested in the reverse transformation. He wants to fold the given sequence in such a way that the resulting folded sequence contains the least possible number of characters.

输入格式

The input contains a single line of characters from 'A' to 'Z' with at least 1 and at most 100 characters.

输出格式

Write to the output a single line that contains the shortest possible folded sequence that unfolds to the sequence that is given in the input file. If there are many such sequences then write any one of them.

样例输入输出

样例输入

AAAAAAAAAABABABCCD

样例输出

9(A)3(AB)CCD

题目概括

给一个字符串,尽量压缩,让他长度最短。()和数字都是算长度的。所以样例里CC才没有变成2(C)

解析

显然,一个字符串的合并方案为将这个字符串压缩还是用两个子串合并起来,两个方案中取最优解。那么我们需要一个最优子结构来记录最长度。当然,为了方便计算,还需要记录这个压后的子串。

既然一个字符串的长度可以由自己的两个子串推出,我们可以以区间的形式,设\(f[i][j]\)表示以第i个字符开头、第j个字符结尾的字符串压缩后的最短长度,\(g[i][j]\)为这个最优的子串。我们以区间DP的形式,首先确定一个区间(i,j),然后分两种情况计算长度。第一种是将其压缩。显然,单位字符串越短结果越优,所以从小到大枚举单位字符串长度,如果可行就直接更新\(f[i][j]\)和\(g[i][j]\)。(具体操作看代码注释)。然后再枚举区间中的点k,那么就有如下动态规划方程:
\[ f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]) \]
如果能够更新\(f[i][j]\),就同时更新\(g[i][j]\)。最后的答案即为\(f[1][n]\)。

代码

//(i,j)表示以第i个字符开头、第j个字符结尾的字符串
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 102
using namespace std;
const int inf=1<<30;
char s[102],g[N][N][N];
int len,f[N][N],i,j,k;
int main()
{
    cin>>s;
    len=strlen(s);
    for(i=0;i<len;i++){
        f[i][i]=1;
        g[i][i][0]=s[i];
    }
    for(i=2;i<=len;i++){
        for(j=0;j+i-1<len;j++){
            int l=j,r=j+i-1;
            f[l][r]=inf;
            for(k=1;k<=(i>>1);k++){
                if(i%k!=0) continue;//只有刚好可以组成整个(i,j)的才能计算
                int tl=l,tr=l+k;
                while(tr<=r&&s[tl]==s[tr]) tl++,tr++;//判断(i,j)是否由(i,i+k-1)构成
                if(tr>r){
                    sprintf(g[l][r],"%d",i/k);
                    strcat(g[l][r],"(");
                    strcat(g[l][r],g[l][l+k-1]);
                    strcat(g[l][r],")");
                    f[l][r]=strlen(g[l][r]);
                    break;
                }
            }
            for(k=l;k<r;k++){
                if(f[l][r]>f[l][k]+f[k+1][r]){
                    f[l][r]=f[l][k]+f[k+1][r];
                    strcpy(g[l][r],g[l][k]);
                    strcat(g[l][r],g[k+1][r]);
                }
            }
        }
    }
    cout<<g[0][len-1]<<endl;
    return 0;
}

标签:unfolds,sequence,Folding,folded,样例,POJ,characters,字符串,2176
来源: https://www.cnblogs.com/LSlzf/p/10804938.html