源程式名 blast.???(pas, c, cpp)
可執行檔名 blast.exe
輸入檔名 blast.in
輸出檔名 blast.out
【問題描述】
設有字串x,我們稱在x的頭尾及中間插入任意多個空格後構成的新字串為x的擴充套件串,如字串x為」abcbcd」,則字串「abcb□cd」,「□a□bcbcd□」和「abcb□cd□」都是x的擴充套件串,這裡「□」代表空格字元。
如果a1是字串a的擴充套件串,b1是字串b的擴充套件串,a1與b1具有相同的長度,那麼我捫定義字串a1與b1的距離為相應位置上的字元的距離總和,而兩個非空格字元的距離定義為它們的ascii碼的差的絕對值,而空格字元與其他任意字元之間的距離為已知的定值k,空格字元與空格字元的距離為0。在字串a、b的所有擴充套件串中,必定存在兩個等長的擴充套件串a1、b1,使得a1與b1之間的距離達到最小,我們將這一距離定義為字串a、b的距離。
請你寫乙個程式,求出字串a、b的距離。
【輸入】
輸入檔案第一行為字串a,第二行為字串b。a、b均由小寫字母組成且長度均不超過2000。第三行為乙個整數k(1≤k≤100),表示空格與其他字元的距離。
【輸出】
輸出檔案僅一行包含乙個整數,表示所求得字串a、b的距離。
【樣例】
blast.in blast.out
cmc 10
snmn
【演算法分析】
字串a和b的擴充套件串最大長度是a和b的長度之和。如字串a為「abcbd」,字串b為「bbcd」,它們的長度分別是la=5、lb=4,則它們的擴充套件串長度最大值為la+lb=9,即a的擴充套件串的5個字元分別對應b的擴充套件串中的5個空格,相應b的擴充套件串的4個字元對應a的擴充套件串中的4個空格。例如下面是兩個字串的長度為9的擴充套件串:
a□b c□b□d□
□b□□b□c□d
而a和b的最短擴充套件串長度為la與lb的較大者,下面是a和b的長度最短的擴充套件串:
a b cbd
b□bcd
因此,兩個字串的等長擴充套件串的數量是非常大的,尋找最佳「匹配」(對應位置字元距離和最小)的任務十分繁重,用窮舉法無法忍受,何況本題字串長度達到2000,巨大的資料規模,勢必啟發我們必須尋求更有效的方法:動態規劃。
記1, a2, …, ai>為a串中a1到ai的乙個擴充套件串,1,b2, …, bj>為b串中b1到bj的乙個擴充套件串。這兩個擴充套件串形成最佳匹配的條件是(1)長度一樣;(2)對應位置字元距離之和最小。
首先分析擴充套件串1, a2, …, ai>與擴充套件串1, b2, …, bj>長度一樣的構造方法。擴充套件串1,a2, …, ai>與擴充套件串1, b2, …, bj>可以從下列三種情況擴張成等長:
(1)1, a2, …, ai>與1, b2, …, bj
-1>為兩個等長的擴充套件串,則在1, a2, …, ai>後加一空格,1, b2, …, bj
-1>加字元bj;
(2)1, a2, …, ai
-1>與1, b2, …, bj>為兩個等長的擴充套件串,則在1,a2, …, ai
-1>新增字元ai,在1, b2, …, bj>後加一空格;
(3)1, a2, …, ai
-1>與1, b2, …, bj
-1>為兩個等長的擴充套件串,則在1, a2, …, ai
-1>後新增字元ai,在1,b2, …, bj
-1>後新增字元bj。
其次,如何使擴充套件成等長的這兩個擴充套件串為最佳匹配,即對應位置字元距離之和最小,其前提是上述三種擴充套件方法中,被擴充套件的三對等長的擴充套件串都應該是最佳匹配,以這三種擴充套件方法形成的等長擴充套件串(a1, a2, …, ai>和1, b2, …, bj>也有三種不同情形,其中對應位置字元距離之和最小的是最佳匹配。
為了能量化上述的構造過程,引入記號g[i, j]為字串a的子串a1, a2, …, ai與字串b的子串b1, b2, …, bj的距離,也就是擴充套件串1, a2, …, ai>與擴充套件串1, b2, …, bj>是乙個最佳匹配。則有下列狀態轉移方程:
g[i, j]=min 0≤i≤la 0≤j≤lb
其中,k位字元與字元之間的距離;為字元ai與字元bi的距離。
初始值:g[0, 0]=0 g[0, j]=j·k g[i, 0]=i·k
綜上所述,本題的主要演算法如下:
(1)資料結構
var a, b:array[1..2000]of byte;
g:array[0..2000, 0..2000]oflongint;
(2)讀入字串a、b,轉換為ascii碼
la:=0; lb:=0;
whilenot(eoln(f)) do
begin
read(f, c);
inc(la);
a[la]:=ord(c);
end;
readln(f);
whilenot(eoln(f)) do
begin
read(f, c);
inc(lb);
b[lb]:=ord(c);
end;
readln(f);
(3)根據狀態轉移方程求g[la, lb]
g[0,0]:=0;
fori:=1 to la do g[i, 0]:=k+g[i-1, 0];
forj:=1 to lb do g[0, j]:=k+g[0, j-1];
fori:=1 to la do
for j:=1 to lb do
begin
g[i, j]:=k+g[i-1,j];
temp:=g[i, j-1]+k;
if g[i, j]>temp theng[i, j]:=temp;
temp:=g[i-1,j-1]+abs(a[i]-b[j]);
if g[i, j]>temp theng[i, j]:=temp;
end;
(4)輸出
writeln(f, g[la, lb]);
#include#include#include#includeusing namespace std;
const int maxn=2010;
char a[maxn];
char b[maxn];
int g[maxn][maxn]=;//陣列g儲存狀態
int k;
int main(void)
// printf("\n");
} printf("%d\n",g[a1][b1]);
return 0;}/*
a1,b1具有相同的長度 相應位置上的距離
空格和非空格之間的差為k
可以轉化為相互對應問題
a1與b1之間的字元相互對應
a[i][j]表示a1的前i個字元與b1的前j個字元對應時的最小距離和
則a[i][j]=
關鍵的問題在於如何表示a1、b1具有相同長度這個狀態
*/
動態規劃訓練題1
小可可選修了基礎生物基因學。教授告訴大家 super samuel 星球上 kitty貓的基因的長度都是 2 的正整數次冪 全是由兩種不同的基因單元組成的。這兩種不同的基因單元分別記成 0 和 1,於是 kitty 貓基因可以寫成乙個 01 串表示式 為了便於分析和降低資料儲存量,教授發明了 abc...
動態規劃訓練日記
1.洛谷p1244青蛙過河 lgp1244青蛙過河 動態規劃 狀態表示 dp i j 表示石墩數量為i,荷葉數量為j時能夠走過青蛙的數量。狀態轉移 因為青蛙在石墩上必須按照漢諾塔的形式排列。所以要從起點走到終點,必須要讓編號最大的青蛙,先跳過去。為了這個目的,我們需要把編號最大的青蛙上面的青蛙全部挪...
動態規劃訓練之十九
題目大意 o n 求出乙個序列的本質不同的子串行個數 考慮動態規劃 dp i 表示前i位子序列的個數 很顯然如果沒有本質不同的話,子串行個數等同於子集的個數就是2n 1 但關鍵就在於這個本質不同?怎麼辦?當然考慮容斥 記vis a i 表示上一次a i 出現的位置 只要dp的時候減掉dp vis a...