大意:找到最小的回文子串个数并输出,学到了回溯方法,因为状态转移,最后这个点更新的就是最优的情况,所以在状态转移这里设立一个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 ",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 ",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(" "); t1++; i = path[i]; } // printf("%d",t1); for(int i = t1 - 1; i >= 1; i--){ for(int j = 1; pri[i][j] != ' ';j++) printf("%c",pri[i][j]); if(i!=1) printf(" "); } printf(" "); } 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 ",dp[len-1]); print(len-1);//dfs printf(" "); } int main() { while(~scanf("%s",s)){ memset(dp,0,sizeof(dp)); memset(pre,0,sizeof(pre)); memset(ok,0,sizeof(ok)); solve(); } return 0; }