大意:找到最小的回文子串个数并输出,学到了回溯方法,因为状态转移,最后这个点更新的就是最优的情况,所以在状态转移这里设立一个path来记录当前这个状态要转移去的下标,然后只要递推就行,自己写的O(n^3)超时了 orz。不过思路很清楚
两种方法..自己调了一下午。。。以为成功了,结果交了两发TLE+MLE两个错误0.0瞬间就惊呆了orz
自己的
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[4200];
int dp[4200];
int b[4200][4200];
int path[4200];
int n;
char pri[4200][4200];
void inti(){
for(int i = 1 ; i <= n; i++){
for(int j = i + 1 ;j <= n; j++){
int k,p;
for( k = i,p = j; k < p; k++,p--){
if(a[k] != a[p] )
break;
}
if(k >= p)
b[i][j] = j - i + 1;
}
}
for(int i = 1 ; i <= n; i++)
b[i][i] = 1;
}
int main()
{
while(~scanf("%s",a+1)){
memset(b,0,sizeof(b));
memset(dp,0,sizeof(dp));
memset(path,0,sizeof(path));
n = strlen(a+1);
inti();
dp[1] = 1;
for(int i = 2 ; i <= n;i++)
dp[i] = dp[i-1]+1;
dp[0] = 0;
for(int i = 1; i <= n; i++){
for(int j = i ; j <= n; j++){
if(dp[j-b[i][j]]+1 <= dp[j]){
dp[j] = dp[j-b[i][j]] + 1;
path[j] = j - b[i][j];
}
}
}
//for(int i = 1; i <= n ;i++)
//printf("%d\n",path[i]);
// for(int i = 1; i <= n; i++)
// for(int j = i+1 ; j <= n;j++)
// printf("%d ",b[i][j]);
// for(int i = 1 ; i <= n; i++)
// printf("%d ",dp[i]);
printf("%d\n",dp[n]);
int i = n ;
int t1 = 1;
int t2;
memset(pri,0,sizeof(pri));
while( i >= 1){
t2 = 1;
for(int j = path[i]+1; j <= i ;j++){
pri[t1][t2++] = a[j];
// printf("%d%d%c ",t1,t2-1,pri[t1][t2-1]);
}
// printf("\n");
t1++;
i = path[i];
}
// printf("%d",t1);
for(int i = t1 - 1; i >= 1; i--){
for(int j = 1; pri[i][j] != '\0';j++)
printf("%c",pri[i][j]);
if(i!=1) printf(" ");
}
printf("\n");
}
return 0;
}
AC的
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[4010];
int pre[4010];
int ok[4010][4010];
char s[4010];
void print(int p)
{
if(pre[p] == -1){
for(int i = 0 ; i <= p ;i++){
printf("%c",s[i]);
}
}
else{
print(pre[p]);
printf(" ");
for(int i = pre[p]+1; i <= p ;i++)
printf("%c",s[i]);
}
}
void solve()
{
int len = strlen(s);
for(int i = 0;i < len ;i++){//i表示长度
for(int j = 0 ;i+j < len;j++){
if(i == 0) ok[j][j+i] = 1; //因为从小到大所以是符合这个方程的
else if(i == 1) ok[j][j+i] = (s[j] == s[j+i]);
else if(s[j] == s[j+i])
ok[j][j+i] = ok[j+1][j+i-1];
}
}
for(int i = 0; i < len ;i++){
dp[i] = i + 1;
pre[i] = i - 1;//从0到i是否回文
if(ok[0][i]) {
dp[i] = 1;
pre[i] = -1;
continue;
}
for(int j = i - 1; j >= 0 ; j--){
if(ok[j+1][i]){//j表示i前面
if(dp[i] > dp[j] + 1){
dp[i] = dp[j] + 1;
pre[i] = j;
}
}
}
}
printf("%d\n",dp[len-1]);
print(len-1);//dfs
printf("\n");
}
int main()
{
while(~scanf("%s",s)){
memset(dp,0,sizeof(dp));
memset(pre,0,sizeof(pre));
memset(ok,0,sizeof(ok));
solve();
}
return 0;
}