DP专练(1):align
http://hi.baidu.com/raulliubo/blog/item/5538f1f88931860bd9f9fd9b.html
顺序对齐
源程序名 ALIGN.??? (PAS,C,CPP)
可执行文件名 ALIGN.EXE
输入文件名 ALIGN.IN
输出文件名 ALIGN.OUT
考虑两个字符串右对齐的最佳解法。例如,有一个右对齐方案中字符串是AADDEFGGHC和ADCDEGH。
AAD_DEFGGHC
ADCDE__GH_
每一个数值匹配的位置值2分,一段连续的空格值-1分。所以总分是匹配点的2倍减去连续空格的段数,在上述给定的例子中,6个位置(A,D,D,E,G,H)匹配,三段空格,所以得分2*6+(-1)*3=9,注意,我们并不处罚左边的不匹配位置。若匹配的位置是两个不同的字符,则既不得分也不失分。
请你写个程序找出最佳右对齐方案。
输入
输入文件包含两行,每行一个字符串,最长50个字符。字符全部是大字字母。
输出
一行,为最佳对齐的得分。
样例
ALIGN.IN
AADDEFGGHC
ADCDEGH
ALIGN.OUT
9
解:
本题解法类似于
我们设f[i][j] 为a串从左到i,b串从左到j的最大得分。
由于最左边的空格不扣分,所以我们可以读入串后将串反过来,这样便好处理了。不过这样最后的答案就不应该是f[lena, lenb]了(想想为什么)。f[lena,lenb]的答案是把最右边的空格的分扣去后的答案(现在的右边既为以前串的左边)。
一共有三种情况
1.在a串和b串后都添加一个字母
如果这两个字母匹配,f[i+1, j+1] 就等于f[i, j] + 2。
两个字母不匹配,f[i+1, j+1]便等于f[i, j]。
2.在b串后添k(k >= 1)个空格,在a串后添加一个字母
枚举空格的长度k,如果f[i+k, j] < f[i, j] – 1则f[i+k, j] 等与f[i, j] -1;
3.在a串后添k(k>=1)个空格,在b串后添加一个字母
枚举空格的长度k,如果f[i, j+k] < f[i, j] – 1则f[i, j+k] 等与f[i, j] -1;
在转移的同时更新最大值max,最后的答案便为max.
程序如下:
var
a, b : string;
f : array[0 .. 50, 0 .. 50] of integer;
max : integer;
procedure init;
var
s : string;
i, j : longint;
begin
assign(input,'align.in'); reset(input);
assign(output,'align.out'); rewrite(output);
max := -1000;
readln(a);
s := a;
for i := 1 to length(s) do
a[length(s) - i + 1] := s[i];
readln(b);
s := b;
for i := 1 to length(s) do
b[length(s) - i + 1] := s[i];
for i := 0 to length(a) do
for j := 0 to length(b) do
f[i, j] := -1000;
f[0, 0] := 0;
end;
procedure dp;
var
i, j, k : integer;
begin
for i := 0 to length(a) do
for j := 0 to length(b) do
if f[i, j] > -1000 then begin
for k := 1 to length(a) do
if i + k <= length(a) then
if f[i + k, j] < f[i, j] - 1 then begin
f[i + k, j] := f[i, j] - 1;
if f[i + k, j] > max then
max := f[i + k, j];
end;
for k := 1 to length(b) do
if j + k <= length(b) then
if f[i, j + k] < f[i, j] - 1 then begin
f[i, j + k] := f[i, j] - 1;
if f[i, j + k] > max then
max := f[i, j + k];
end;
if (i + 1 <= length(a)) and (j + 1 <= length(b)) then
if a[i + 1] = b[j + 1] then begin
if f[i + 1, j + 1] < f[i, j] + 2 then begin
f[i + 1, j + 1] := f[i, j] + 2;
if f[i + 1, j + 1] > max then
max := f[i + 1, j + 1];
end;
end
else begin
if f[i + 1, j + 1] < f[i, j] then begin
f[i + 1, j + 1] := f[i, j];
if f[i + 1, j + 1] > max then
max := f[i + 1, j + 1];
end;
end;
end;
writeln(max);
close(input); close(output);
end;
begin
init;
dp;
end.
LCS。