【DP,lcs问题】最短回文串(palindrome.pas/c/cpp)

 最短回文串(palindrome.pas/c/cpp)

如果一个字符串正过来读和倒过来读是一样的,那么这个字符串就被称作回文串。例如
abcdcba,abcddbca就是回文串,而abcdabcd 不是。
    你要解决的问题是:对于任意一个字符串,输出将这个字符串变为回文串需要插入的最
少字符个数,比如,ab3bd 只需要插入2个字符就可以变为一个回文串。

输入数据
    第一行是一个整数N
    第二行是一个长度为N 字符串S

输出数据
    一行一个整数,表示将S变为回文串需要插入的最小字符个数

样例
    输入
    5
    ab3bd

    输出
    2

数据范围
    对于所有数据,0<n<=5000
=========================

有两种方法:

1.直接求

2.利用lcs知识,求最长公共子序列..最小插入的字符个数就是原串长度-最长公共子序列长度..

我用的是第一种方法...

=====================================================================

第一种方法的

第一种方案:

   开两个数组,将串正存和反存... 

   方程 f[i,j]表示第一个数组达到i第二个数组达到j的最优值

            有两种转移..if a[i]=b[j] then f[i,j]:=min(f[i-1,j-1],f[i,j])

                                                  else  begin
                                                                f[i,j]:=min(f[i,j],f[i,j+1]+1);
                                                                f[i,j]:=min(f[i,j],f[i-1,j]+1);   
                                                           end;

但是要注意过多调用过程会超时

------------------------------------------------------------------------------------    

var
  n,ans:longint;
  a,b:array[0..5000]of char;
  f:array[0..5000,0..5000]of longint;
procedure init;
begin
  assign(input,'palindrome.in');
  assign(output,'palindrome.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

function min(a,b:longint):longint;
begin
  if a>b then exit(b);
  exit(a);
end;

procedure main;
var
  i,j:longint;
begin
  readln(n);
  for i:=1 to n do
    begin
      read(a[i]);
      b[n+1-i]:=a[i];
    end;
  fillchar(f,sizeof(f),$7);
  f[0,0]:=0;
  ans:=maxlongint;
  for i:=1 to n do begin f[i,0]:=i; f[0,i]:=i; end;
  for i:=1 to n do
    for j:=1 to n do
      begin
        if a[i]=b[j] then begin if f[i,j]>=f[i-1,j-1] then f[i,j]:=f[i-1,j-1] end // f[i,j]:=min(f[i,j],f[i-1,j-1]) 
                     else begin
                            //f[i,j]:=min(f[i,j],f[i-1,j]+1);
                           // f[i,j]:=min(f[i,j],f[i,j-1]+1);
                            if f[i-1,j]+1<f[i,j] then f[i,j]:=f[i-1,j]+1;
                            if f[i,j-1]+1<f[i,j] then f[i,j]:=f[i,j-1]+1;
                            //f[i,j]:=min(f[i,j],f[i-1,j-1]+2);
                          end;
        //if i+j-1=n then if f[i,j]<ans then ans:=f[i,j];
      end;
  writeln(f[n,n]div 2);
  //writeln(ans);
end;

begin
  init;
  main;
  terminate;
end.

=================================================

第二种方案
   f[i,j]表示串从1到i和从n到j的最优值

           转移方式:if pal[i]=pal[j] then f[i,j]:=min(f[i,j],f[i-1,j+1])
                                else begin
                                            f[i,j]:=min(f[i,j],f[i,j+1]+1);
                                            f[i,j]:=min(f[i,j],f[i-1,j]+1);   
                                        end;   

----------------------------------------

但是我不知道哪个地方写错了..错了一个点..希望看见此文章的同学帮我指点下错误

--------------------------------------------------------------------------------------------------------------------

 

var
  n:longint;
  pal:array[0..5000]of char;
  f:array[0..5002,0..5002]of longint;
procedure init;
begin
  assign(input,'palindrome.in');
  assign(output,'palindrome.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

function min(a,b:longint):longint;
begin
  if a>b then exit(b);
  exit(a);
end;

procedure main;
var
  i,j,ans:longint;
begin
  readln(n);
  for i:=1 to n do read(pal[i]);
  
  fillchar(f,sizeof(f),$7);
  
  f[0,n+1]:=0;
  for i:=1 to n do
   begin
    f[0,n-i+1]:=i; 
    f[i,0]:=i;
   end;
  
  for i:=1 to n do
    for j:=n downto i+1 do
      begin
        if pal[i]=pal[j] then f[i,j]:=min(f[i,j],f[i-1,j+1])
                         else begin
                                f[i,j]:=min(f[i,j],f[i,j+1]+1);
                                f[i,j]:=min(f[i,j],f[i-1,j]+1);   
                              end; 
      end;
  ans:=n;
  for i:=1 to n do
    if ans>f[i,i+2] then ans:=f[i,i+2];
  for i:=1 to n do
    if ans>f[i,i+1] then ans:=f[i,i+1];
  //for i:=1 to n do
    //if ans>f[i,i+1] then ans:=f[i,i+1];
  writeln(ans);
end;

begin
  init;
  main;
  terminate;
end.


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值