原題:
In this problem you are asked to convert a string into a palindrome with minimum number of operations.
The operations are described below:
Here you’d have the ultimate freedom. You are allowed to:
• Add any character at any position
• Remove any character from any position
• Replace any character at any position with another character
Every operation you do on the string would count for a unit cost. You’d have to keep that as low
as possible.
For example, to convert “abccda” you would need at least two operations if we allowed you only to
add characters. But when you have the option to replace any character you can do it with only one
operation. We hope you’d be able to use this feature to your advantage.
大意:
給你一個字串,讓你隨意添加,刪除,替換,問你最少多少步操作能把這個字串變成迴文。
#include<iostream>#include<algorithm>#include<map>#include<string>#include<cstring>#include<sstream>#include<cstdio>#include<vector>#include<cmath>#include<stack>#include<queue>#include<iomanip>#include<set>#include<fstream>using namespace std;int dp[1001][1001];int min3(int x,int y,int z){ return min(min(x,y),min(x,z));}int main(){ ios::sync_with_stdio(false); int n; string s; cin>>n; for(int k=1;k<=n;k++) { cin>>s; memset(dp,0,sizeof(dp)); for(int i=s.size()-1;i>=0;i--) { for(int j=i+1;j<s.size();j++) { if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]; else dp[i][j]=min3(dp[i+1][j],dp[i][j-1],dp[i+1][j-1])+1; } } cout<<"Case "<<k<<": "<<dp[0][s.size()-1]<<endl; }// input.close();// output.close(); return 0;}
解答:
首先要能想到這是一個區間的動態規劃問題,單純考慮一個方向進行最優解是考慮不出來的。現在考慮兩個方向,即設定dp[i][j]表示i到j這部分字串所形成的迴文需要多少步最少的操作。
接下來考慮狀態轉移,題目中給出的狀態轉移有3種方式,增加,替換,刪除。其中增加和刪除的效果是一樣的,而且每次增加或者刪除目的都是為了形成一個迴文串,例如在字串si….sj中,dp[i][j] =dp[i][j-1]+1可以表示為把第j個刪除,也可以表示為在i前面加上一個字元(注意此時的si變成si+1)。如果是替換就是強行讓第i個字元和第j個字元相同,也就是dp[i][j]=dp[i+1][j-1]+1。 所以轉移方程就會是dp[i][j]=min(dp[i+1][j],dp[i][j-1],dp[i+1][j-1])+1(當s[i]!=s[j])時。