假设有指针i,j指向字符串的首尾,即初值为0,n-1。
如果字符相等,则总插入次数等于字符串(i+1,j-1)的总插入次数。
如果字符不相等,则有在i处插入一个和j处相等的字符和在j处插入和i处相等的字符两种选择,选择的依据是字符串(i,j-1)总插入次数和字符串(i+1,j)哪个小。
由此子问题和递推关系都有了。
然后是边界条件。设字符串(i,j)总插入次数是res[i][j]。
注意到i<j,因此只需要计算一半的矩阵。边界有i=j时,res[i][j]=0。
计算每个子问题,最后矩阵右上角res[0][n-1]即为所求。
#include<iostream> #include<fstream> using namespace std; int n; char str[5001]; short res[5002][5002]; int main(){ streambuf *backup; ifstream fin; fin.open("data.in"); backup = cin.rdbuf(); // back up cin's streambuf cin.rdbuf(fin.rdbuf()); // assign file's streambuf to cin cin>>n; cin>>str; memset(res,0,sizeof(res)); for(int i=0;i<n;i++){ res[i][i]=0; } for(int i=0;i<n-1;i++){ res[i][i+1]=(str[i]==str[i+1]?0:1); } int x; for(int i=2;i<n;i++){ x=0; for(int y=i;y<n;y++){ if(str[x]==str[y]){ res[x][y]=res[x+1][y-1]; }else{ res[x][y]=min(res[x+1][y],res[x][y-1])+1; } x++; } } cout<<res[0][n-1]<<endl; return 0; }但是这样做时间空间消耗都很大。我想到不一定每个子问题都用得到,因为当两个字符相等的时候只用了res[x+1][y-1],那么res[x+1][y]和res[x][y-1]就不用计算了,那么相关的一连串子问题都不用计算了。所以我又自顶向下用了递归,但是还是把结果保存,仍然是dp。
#include<iostream> #include<fstream> using namespace std; int n; char str[5001]; short res[5002][5002]; short f(int x,int y){ if(res[x][y]==-1){ if(str[x]==str[y]){ res[x][y]=f(x+1,y-1); }else{ res[x][y]=min(f(x+1,y),f(x,y-1))+1; } } return res[x][y]; } int main(){ streambuf *backup; ifstream fin; fin.open("data.in"); backup = cin.rdbuf(); // back up cin's streambuf cin.rdbuf(fin.rdbuf()); // assign file's streambuf to cin cin>>n; cin>>str; memset(res,-1,sizeof(res)); for(int i=0;i<n;i++){ res[i][i]=0; } for(int i=0;i<n-1;i++){ res[i][i+1]=(str[i]==str[i+1]?0:1); } cout<<f(0,n-1)<<endl; return 0; }poj提交上去,效率提升并不大,不过我觉得总体来说应该还是有一定提升效率的作用。
进一步研究空间,可以发现矩阵只用了一半,另一半完全可以舍弃,另外,每回合计算只涉及到与对角线平行的三条线(画矩阵就看出来了),因此res有三行就够了。把上面代码用到的index映射到这三行,三行一直roll着用就可以了。
#include<iostream> #include<fstream> using namespace std; int n; char str[5001]; short res[3][5002]; int main(){ //streambuf *backup; // ifstream fin; // fin.open("data.in"); // backup = cin.rdbuf(); // back up cin's streambuf // cin.rdbuf(fin.rdbuf()); // assign file's streambuf to cin // cin>>n; cin>>str; memset(res,0,sizeof(res)); int s,m,e,y; s=0;m=1;e=2; for(int i=1;i<n;i++){ y=i; for(int x=0;x<n-i;x++){ if(str[x]==str[y]){ res[e][x]=res[s][x+1]; }else{ res[e][x]=min(res[m][x],res[m][x+1])+1; } y++; } if(i!=n-1){ s=(s+1)%3; m=(m+1)%3; e=(e+1)%3; } } cout<<res[e][0]<<endl; return 0; }