回文串dp问题
判断最长回文串
bool dp[i][j]
表示从[i,j]这一段是否为回文串- 状态转移方程:
dp[i][j] = (s[i] == s[j] && (j-i == 1||dp[i+1]dp[j-1]))?true:false (j > i)
- j-i == 1 是对aa这种两个字符呈对称形式的情况
#include <iostream>
using namespace std;
#define maxn 10010
char s[maxn];
int main(int argc, const char * argv[]) {
scanf("%s",s);
int len = strlen(s),ans = 0;
bool dp[len][len];
for (int i = 0; i < len; i++) dp[i][i] = true;
for (int j = 1; j < len; j++)
for (int i = 0; i < j; i++)
if (s[i] == s[j] && (j-i == 1 || dp[i+1][j-1])) {dp[i][j] = true;ans = max(ans,j-i+1);}
else dp[i][j] = false;
printf("%d\n",ans);
return 0;
}
以回文串形式抽取字串的最小次数
- dp[i][j]表示区间[i,j]的最少抽取次数
- 状态转移方程
if (s[i] == s[j]) dp[i][j] = (j-i == 1)?1:dp[i+1][j-1]
dp[i][j] = min(dp[i][k]+dp[k+1][j],dp[i][j])
#include <iostream>
using namespace std;
#include <cstring>
#define cl(a,b) memset(a,b,sizeof(a))
#include <string>
#define maxn 505
int dp[maxn][maxn],a[maxn];
int n,len,i,j,k;
#define INF 0x3f3f3f
int main(int argc, const char * argv[]) {
scanf("%d",&n);
cl(dp, INF);
for (i = 1; i <= n; i++) {
scanf("%d",&a[i]);
dp[i][i] = 1;
}
for (len = 1; len < n; len++)
for (i = 1; i+len <= n; i++) {
j = i+len;
if (a[i] == a[j])
dp[i][j] = len == 1?1:dp[i+1][j-1];
for (k = i; k < j; k++) dp[i][j] = min(dp[i][k]+dp[k+1][j],dp[i][j]);
}
cout<<dp[1][n]<<endl;
return 0;
}
非回文串添加字符变成回文串的最小字符数
CSUOJ2358