zoukankan      html  css  js  c++  java
  • [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:

    • A sequence that contains a single character from 'A' to 'Z' is considered to be a folded sequence. Unfolding of this sequence produces the same sequence of a single character itself.
    • If S and Q are folded sequences, then SQ is also a folded sequence. If S unfolds to S' and Q unfolds to Q', then SQ unfolds to S'Q'.
    • If S is a folded sequence, then X(S) is also a folded sequence, where X is a decimal representation of an integer number greater than 1. If S unfolds to S', then X(S) unfolds to S' repeated X times.

    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;
    }
    
  • 相关阅读:
    TCP三次握手四次挥手
    TCP与UDP的区别
    mysql从库设置全局只读,并创建普通账号
    docker安装mysql主从
    mysql 更换数据目录
    Docker 部署 ElasticSearch
    js获取地址栏传参
    PHP-MySQL基本操作
    基于element-tree-table树型表格点击节点请求数据展开树型表格
    拖拽读取文件
  • 原文地址:https://www.cnblogs.com/LSlzf/p/10804938.html
Copyright © 2011-2022 走看看