题目大意:
问有几种删除字符的方法可以使得该字符串为回文。
思路:
记忆化搜索。
状态转移方程:
if(s[i] == s[j]) , 那么 dp[i][j] = dp[i + 1][j] + dp[i][ j - 1] - dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1;
dp[i][j]表示的是从i到j最多可以有几个不同的回文串。 回文串不同那么自然删除的方法就不一样了。
dp[i][j] 是由 i + 1到j的回文串数和i到j - 1的回文串数组成的,然而中间的i + 1到j - 1的回文串多算了一次 因此要减去,但是s[i] == s[j]的时候,i + 1 到j - 1的每个回文串都可以与 s[i],s[j]组成一个新的回文串,因此要加上dp[i + 1][j - 1] + 1。
if(s[i] != s[j]) 那么dp[i][j] = dp[i + 1][j] + dp[i][ j - 1] - dp[i + 1][j - 1];
代码:
#include <iostream>
using namespace std;
#include <stdio.h>
#include <cstring>
char s[65];
long long dp[105][105];
bool vis[105][105];
long long d(int i,int j) {
long long & ans = dp[i][j];
if(vis[i][j]) return ans;
vis[i][j] = 1;
if(i > j) ans = 0;
else if(i == j) ans = 1;
else if(s[i] == s[j]) {
ans = d(i,j - 1) + d(i + 1,j) + 1;
}
else {
ans = d(i,j - 1) + d(i + 1, j) - d(i + 1, j - 1);
}
return ans;
}
int main() {
int n;
scanf("%d",&n);
getchar();
while(n--) {
gets(s);
int len =strlen(s);
for(int i = 0;i < len; i++)
dp[i][i] = 1;
memset(vis,0,sizeof(vis));
long long ans = d(0,len - 1);
/* for(int i = len - 1; i >= 0; i--) {
for(int j = i + 1; j < len; j++) {
if(s[i] == s[j])
dp[i][j] = dp[i + 1][j] + dp[i][j - 1] + 1;
else {
dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
if(ans < dp[i][j])
ans = dp[i][j];
}
}
}*/
printf("%lld\n",ans);
}
return 0;
}
第二种:
#include <iostream>
using namespace std;
#include <stdio.h>
#include <cstring>
char s[65];
long long dp[105][105];
bool vis[105][105];
/*long long d(int i,int j) {
long long & ans = dp[i][j];
if(vis[i][j]) return ans;
vis[i][j] = 1;
if(i > j) ans = 0;
else if(i == j) ans = 1;
else if(s[i] == s[j]) {
ans = d(i,j - 1) + d(i + 1,j) + 1;
}
else {
ans = d(i,j - 1) + d(i + 1, j) - d(i + 1, j - 1);
}
return ans;
}*/
int main() {
int n;
scanf("%d",&n);
getchar();
while(n--) {
gets(s);
int len =strlen(s);
for(int i = 0;i < len; i++)
dp[i][i] = 1;
memset(vis,0,sizeof(vis));
// long long ans = d(0,len - 1);
// long long ans = 0;
for(int i = len - 1; i >= 0; i--) {
for(int j = i + 1; j < len; j++) {
if(s[i] == s[j])
dp[i][j] = dp[i + 1][j] + dp[i][j - 1] + 1;
else {
dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
// if(ans < dp[i][j])
// ans = dp[i][j];
}
}
}
printf("%lld\n",dp[0][len - 1]);
}
return 0;
}