题意:给出一个由大写字母组成的长度为n(n <= 100)的串,“折叠”成一个尽量短的串.
分析:f[i][j]表示把i到j这一段压缩后的最小长度,那么f[i][j] = min(f[i][k]+f[k+1][j]),如果[i,j]这一子串存在循环节的话还要处理一下折叠的情况.
#include <bits/stdc++.h>
#define N 100005
#define INF 1047483647
using namespace std;
typedef pair<int,int> pii;
string cho[105][105],str;
int n,vis[105][105],f[105][105],T,Next[105];
int kmp(string s)
{
int m = s.length();
memset(Next,0,sizeof(int)*(m+2));
int now = Next[0] = -1;
for(int i = 1;i < m;i++)
{
while(now >= 0 && s[now+1] != s[i]) now = Next[now];
if(s[now+1] == s[i]) now++;
Next[i] = now;
}
return (m - 1 - Next[m-1]);
}
void dfs(int l,int r)
{
if(vis[l][r] == T) return;
vis[l][r] = T;
f[l][r] = r-l+1;
cho[l][r] = str.substr(l-1,r-l+1);
for(int i = l;i < r;i++)
{
dfs(l,i);
dfs(i+1,r);
if(f[l][i] + f[i+1][r] < f[l][r])
{
f[l][r] = f[l][i] + f[i+1][r];
cho[l][r] = cho[l][i] + cho[i+1][r];
}
}
int circle = kmp(str.substr(l-1,r-l+1));
if(circle < r-l+1 && ((r-l+1) % circle == 0))
{
int t = (r-l+1)/circle;
string temp;
if(t == 100) temp += "100";
else
{
if(t >= 10) temp += char(t/10+'0');
temp += char(t%10+'0');
}
dfs(l,l+circle-1);
temp += "("+cho[l][l+circle-1]+")";
if(temp.length() < f[l][r])
{
f[l][r] = temp.length();
cho[l][r] = temp;
}
}
}
int main()
{
while(cin>>str)
{
++T;
int n = str.length();
dfs(1,n);
cout<<cho[1][n]<<endl;
}
}