您的位置:首页 > 其它

Uva 1630 折叠串

2017-01-01 11:07 309 查看
题目链接:https://uva.onlinejudge.org/external/16/1630.pdf

题意:折叠串,给一个字符串,相同部分可以折叠,折叠可以嵌套。求最短长度的一种折叠方法。括号和数字的长度也要考虑进去。

刚看到这个题目,没有一点思路,还是大牛们厉害!

分析:一个串,可以转成两种形式,要么本身可以转成有重叠部分的串,要么分成两个部分,再转成有重叠部分的串。

本身是否是重叠串,利用kmp查,分成两个部分,遍历一遍所有情况,这样,dp顺序就出来了,最外层是每次查的长度,第二层就是,利用这个长度,从每一个点开始查起。状态描叙是d[i][j]从 i 到 j 的最短字符串。

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

const int maxn = 100 + 10;

string d[maxn][maxn];
char s[maxn],t[maxn];

int f[maxn];

string ToString(int x)
{
string ans = "";
while(x)
{
ans +=(char)('0'+(x%10));
x/=10;
}
reverse(ans.begin(),ans.end());
return ans;
}

void getFail(char* s)
{
int len = strlen(s);
f[0] = f[1] = 0;
for(int i=1; i<len; i++)
{
int j = f[i];
while(j&&s[i]!=s[j])
j = f[j];
f[i+1] = s[i]==s[j] ? j+1:0;
}
}

int main()
{
while(scanf("%s",s)!=EOF)
{
int len = strlen(s);
for(int i=0; i<len; i++)
d[i][i] = string("")+s[i];

for(int l=2; l<=len; l++)
{
for(int i=0; i + l - 1 < len; i++)
{
int j = i + l - 1;
d[i][j] = "";
for(int k=i; k<=j; k++)
{
d[i][j] +=s[k];
t[k-i] = s[k];
}

t[j-i+1] = 0;
getFail(t);
if(l%(l-f[l])==0)   //自身是重复的
{
int cycle = l - f[l];
string t = "";
t = ToString(l/cycle);
t+='(';
t+=d[i][i+cycle-1];
t+=')';
if(t.length()<d[i][j].length()) d[i][j] = t;
}

for(int k=i; k<j; k++)
{
if(d[i][k].length()+d[k+1][j].length()<d[i][j].length())
{
d[i][j] = d[i][k] + d[k+1][j];
}
}
}
}
cout<<d[0][len-1]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: