-
ABAD
样例输出 -
1
描述
给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串?
一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符。
输入
字符串 S。S 的长度不超过100, 只包含'A'-'Z'。
输出
最少的修改次数。
这道题是一个很经典的动态规划题。
首先要明白,删除操作实际上和增添操作是一模一样的操作。
假设字符串为s。dp[a][b]表示从s[a]到s[b]这一小段子串改成回文串所需要的最小操作步骤。
那么
1、如果s[a]=s[b]也就是,该小段子串首尾两个字符已经一样,则dp[a][b]=dp[a+1][b-1]。也就是说,如果s串为abcdeca,首尾两个字符已经一样,不需要改动,则看bcdec这一小段。
2、如果s[a]!=s[b],则有:
(1)、在s[a]前面添加一个字符,使得这个字符能够和s[b]匹配。则dp[a][b]=dp[a][b-1]+1。也就是说,如果s串为abcbcdb,那么在前面添加一个b可以匹配最后一个字符。所以这一小段的操作步骤就等于abcbcd这一小段的步骤+1。
(2)、在s[b]后面添加一个字符,使得这个字符能够和s[a]匹配,则dp[a][b]=dp[a+1][b]+1,。原因类似上一条。
(3)、改变s[a]或者s[b]的值,使得它能够和s[b]或者s[a]匹配,则dp[a][b]=dp[a+1][b-1]+1.原因类似首尾字符相等的情况。
综上,当s[a]!=s[b]的时候,取三种情况的最小值。
由于是利用动态规划求解,所以在求当前状态的时候,上一个状态一定要已经求得。注意for循环的循环方式。
#include<bits/stdc++.h>
using namespace std;
int dp[110][110];
int Min(int a,int b,int c)
{
return min(min(a,b),c);
}
int main()
{
string s;
while(cin>>s)
{
memset(dp,0,sizeof(dp));
int n=s.length();
for(int i=0; i<n; i++)
for(int j=i-1; j>=0; j--)
{
if(s[i]==s[j])
dp[j][i]=dp[j+1][i-1];
else
dp[j][i]=Min(dp[j+1][i-1],dp[j][i-1],dp[j+1][i])+1;
}
cout<<dp[0][n-1]<<endl;
}
return 0;
}