C語言(CED)最長公共子序列----動態規劃第一題

一、動態規劃算法與分治法的異同

相同點

A、二者均是將待求解的問題分成若干子問題來求解。? ? ? ? ??

B、二者在編寫代碼的時候,都要用到遞歸

不同點

A、分治法求解的問題,在將問題分成若干子問題之后,其子問題之間是獨立存在的,沒有相互關聯。而動態規劃問題劃分后得到的子問題之間相互關聯。

B、動態規劃問題在求解時需要一個表來記錄已解決的子問題的答案,從而避免大量的重復計算。動態規劃算法適合用于解最優化問題。這就表明這類最優化問題可能有很多解,但不一定都是最優解,而利用本算法找出的解可能還是眾多最優解里的一個

二、最優解問題結構性質

最優子結構:當問題的最優解包含了其子問題的最優解時,稱該問題具有最優子結構性質。

重疊子問題:在用遞歸算法自頂向下解決問題的時候,每次產生的子問題并不總是新問題,有些子問題被反復計算。動態規劃算法正式利用這種子問題的重疊性質,對每個子問題只解一次,并將其保存在表格中。

從一般意義上來講,問題所具有的這兩個重要性質是該問題可用動態規劃算法求解的基本要素。

三、動態規劃問題分析及解決步驟

A、找出最優解的性質,刻畫其結構特征。

B、遞歸定義最優值

C、自底向上計算最優值(最優值只是一個結果,最優解是一個過程)

D、根據得到的信息構造最優解(A-C是動態規劃算法的進本步驟,此步在需要求出問題的最優解時才需執行)

好了,有了上面動態規劃的基礎知識后,我們開始本文的“重頭戲”——最長公共子序列。

四、問題描述(問題大意)

子序列:一個給定序列中,刪除若干元素后得到的序列,就是該序列的子序列。

公共子序列:如果有兩個序列按照上述步驟之后得到的子序列相同,那么這個子序列被稱為這兩個序列的公共子序列。

例:有如下兩個序列

X={A、B、C、B、D、A、B},Y={B、D、C、A、B、A}

則序列Z={B、C、A}就是二者的公共子序列,那么什么是最長的公共子序列,大家應該知道了吧?

在這里需要說明的是:一個長度為n的序列,它一共有2的n次方個子序列,有(2^n?– 1)個非空子序列。大家需要注意的是,這里說的是序列,和原來的順序有關聯,而不是高中所學無序的集合。

下面將按照動態規劃算法設計的步驟來設計解決此問題的算法

1、問題結構

?上述證明之后,本問題具有最優子結構性質。

2、遞歸結構

要找出X={x1,x2,...,xm}和Y={y1,y2,...,yn}的最長公共子序列,可按照以下方式遞歸:

A、當Xm=Yn時,找出Xm-1和Yn-1的最長公共子序列,然后在其尾部加上Xm(Xm=Yn),即可得X、Y的最長公共子序列。

B、當Xm!=Yn時,則得解決兩個子問題:Xm-1和Y的一個最長公共子序列及X和Yn-1的一個最長公共子序列,二者中較長者即為X和Y的最長公共子序列。

由這個遞歸結構來看,此問題具有子問題重疊性質,例如:在計算X和Y的最長公共子序列時,可能要計算X和Yn-1及Xm-1和Y的最長公共子序列,這兩個子問題都包含一個公共子問題,即要計算Xm-1和Yn-1的最長公共子序列。

首先建立子問題最優值的遞歸關系,用從c[i][j]記錄序列Xi和Yi的最長公共子序列的長度。其中,Xi={x1,x2,...,xi};Yj={y1,y2,...,yj}

當i=0或j=0時,空序列是Xi和Yj的最長公共子序列,所以此時c[i][j]=0;

其他情況:

A、i>0;j=0時,c[i][j]=0;

B、i,j>0;Xi=Yj時,c[i][j]=c[i-1][j-1]+1

C、i,j>0;Xi!=Yj時,c[i][j]=max{c[i][j-1],c[i-1][j]}

3、計算最優值

直接利用上述遞歸式,寫出代碼。其中X,Y是輸入的兩個序列, ,b[i][j]記錄c[i][j]的值是由哪個子問題的解得來的,這在構造最長公共子序列時要用到。

void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{int i,j;for(i=1;i<=m;i++)//當j=0時,c[i][j]=0c[i][0]=0;for(j=1;j<=n;j++)//當i=0時,c[i][j]=0c[0][j]=0;for(i=1;i<=m;i++)//對最長公共子序列的長度進行記錄for(j=1;j<=n;j++){if(x[i]==y[j])//Xi=Yj的情況{c[i][j]=c[i-1][j-1]+1;//c[i][j]存儲Xi和Yj的最長公共子序列的長度b[i][j]=1; //斜向上           //b[i][j]記錄c[i][j]的值是由哪個子問題的解得來的}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;//豎直向上}else{c[i][j]=c[i][j-1];b[i][j]=3;//水平向左}}
}

4、構造最長公共子序列

用二維數組b快速構造序列X和Y的最長公共子序列。首先從b[m][n]開始,依照其值在數組b中搜索。

A、當在b[i][j]=1時,表示Xi和Yi的最長公共子序列是由Xi-1和Yi-1的最長公共子序列在尾部加上Xi所得到的。

B、當在b[i][j]=2時,表示Xi和Yj的最長公共子序列與Xi-1和Yj的最長公共子序列相同。

C、當在b[i][j]=3時,表示Xi和Yj的最長公共子序列與Xi和Yj-1的最長公共子序列相同。

如此,將最長公共子序列打印出來。代碼如下:

void LCS(int i,int j,char x[], int b[][50])
{if(i==0||j==0)return;if(b[i][j]==1)//表示Xi和Yi的最長公共子序列是由Xi-1和Yi-1的最長公共子序列在尾部加上Xi所得到的{//b[i][j]==1時,表示左斜45°向上,也即這個時候對應的字母時LCS中的一個。LCS(i-1,j-1,x,b);cout<<x[i]<<" ";}else if(b[i][j]==2)//表示Xi和Yj的最長公共子序列與Xi-1和Yj的最長公共子序列相同。LCS(i-1,j,x,b);else//表示Xi和Yj的最長公共子序列與Xi和Yj-1的最長公共子序列相同。LCS(i,j-1,x,b);
}

所以,上述的所有步驟轉變為完整代碼如下:

#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;
int c[50][50];
int b[50][50];
char x[1000];//存放X字符串
char y[1000];//存放Y字符串
void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{int i,j;for(i=1;i<=m;i++)//當j=0時,c[i][j]=0c[i][0]=0;for(j=1;j<=n;j++)//當i=0時,c[i][j]=0c[0][j]=0;for(i=1;i<=m;i++)//對最長公共子序列的長度進行記錄for(j=1;j<=n;j++){if(x[i]==y[j])//Xi=Yj的情況{c[i][j]=c[i-1][j-1]+1;//c[i][j]存儲Xi和Yj的最長公共子序列的長度b[i][j]=1; //斜向上           //b[i][j]記錄c[i][j]的值是由哪個子問題的解得來的}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;//豎直向上}else{c[i][j]=c[i][j-1];b[i][j]=3;//水平向左}}
}
void LCS(int i,int j,char x[], int b[][50])
{if(i==0||j==0)return;if(b[i][j]==1)//表示Xi和Yi的最長公共子序列是由Xi-1和Yi-1的最長公共子序列在尾部加上Xi所得到的{//b[i][j]==1時,表示左斜45°向上,也即這個時候對應的字母時LCS中的一個。LCS(i-1,j-1,x,b);cout<<x[i]<<" ";}else if(b[i][j]==2)//表示Xi和Yj的最長公共子序列與Xi-1和Yj的最長公共子序列相同。LCS(i-1,j,x,b);else//表示Xi和Yj的最長公共子序列與Xi和Yj-1的最長公共子序列相同。LCS(i,j-1,x,b);
}
int main()
{int xn,yn;//XY字符串的大小cout<<"請輸入X集合的元素個數:"<<endl;cin>>xn;cout<<"請輸入X集合的元素:"<<endl;int i=0;//用于循環輸入X和Y的字符串for(i=1;i<=xn;i++)cin>>x[i];cout<<"請輸入y集合的元素個數:"<<endl;cin>>yn;cout<<"請輸入y集合的元素:"<<endl;for(i=1;i<=yn;i++)cin>>y[i];LCSLength(xn,yn,x,y,c,b);cout << "X和Y的最長公共子序列為:";LCS(xn,yn,x,b);cout << endl;int j = 0;int m = 0;printf("b[i][j]中的數字:\n");for (i = 0; i <=xn; i++)for (j = 0; j <= yn; j++){ printf("%d ", b[i][j]);m++;if (m == xn){m = 0;printf("\n");}}m = 0;printf("c[i][j]中的數字:\n");for (i = 0; i <= xn; i++)for (j = 0; j <=yn; j++){printf("%d ", c[i][j]);m++;if (m == xn){printf("\n");m = 0;}}	system("pause");return 0;
}

把c[i][j]和b[i][j]對應起來之后,得到下圖:

從下圖中可以看出,用二維數組b[i][j]中的信息可以構建出X和Y的一個最長公共子序列。從b[xn][yn]開始,沿著橘黃色的箭頭方向追蹤:

A、b[i][j]等于1時,左斜45°向上跳,并且起跳的字母就是LCS的一個成員

B、b[i][j]等于2時,豎直向上跳。

C、b[i][j]等于3時,水平向左跳。

參考:《計算機算法設計與分析·第五版 》王曉東編著

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531098.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531098.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531098.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言(CED)01背包——動態規劃第二題

一、問題描述 給定n種物品和一個背包。物品i的質量Wi&#xff0c;其價值Vi&#xff0c;背包的容量為c。問如何選擇裝入背包中的物品&#xff0c;使得裝入背包中的物品總價值最大&#xff1f; 二、解題思想 01背包和最長公共子序列都是動態規劃題目中求最優解的問題&#xff0…

C語言(CED)gameboy接餡餅問題

一、題目大意 都說天上不會掉餡餅&#xff0c;但有一天gameboy正走在回家的小徑上&#xff0c;忽然天上掉下大把大把的餡餅。這餡餅別處都不掉&#xff0c;就掉落在他身旁的10米范圍內。餡餅如果掉在了地上當然就不能吃了&#xff0c;所以gameboy馬上卸下身上的背包去接。但由…

C語言(CED)遞歸實現漢諾塔問題

一、問題大意 大梵天創造世界的時候做了三根金剛石柱子&#xff0c;在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定&#xff0c;任何時候&#xff0c;在小圓盤上都不能放大圓盤&#xff0c;…

C語言(CED)智力大沖浪——貪心算法第一題

一、題目大意 小偉報名參加中央電視臺的智力大沖浪節目&#xff0c;本次挑戰賽吸引了眾多參賽者&#xff0c;主持人為了表彰大家的勇氣&#xff0c;先獎勵每個參賽者m元。先不要太高興&#xff01;因為這些錢還不一定都是你的&#xff01;接下來主持人宣布了比賽規則&#xff…

C語言(CED)鋼條最優切割收益

目錄 一、題目大意 二、大致思路 三、具體實現 一、題目大意 一家公司購買長鋼條&#xff0c;將其切割成短鋼條出售&#xff0c;切割本身沒有成本&#xff0c;長度為i的短鋼條的價格為Pi。那給定一段長度為n的鋼條和一個價格表Pi,求鋼條的切割方案使得收益Rn最大。提示&…

C語言(CED)如何用sort函數根據結構體里的某一屬性進行排序

&#xff08;請先看置頂博文&#xff09;本博打開方式&#xff0c;請詳讀_liO_Oil的博客-CSDN博客_怎么把androidstudio卸載干凈 前幾天在編寫代碼的時候&#xff0c;突然要根據結構體的屬性進行從小到大的排序&#xff0c;這即是我寫這篇文章的導火索。 正如大家所知…

撰寫paper時,如何在word里輸入圖片或其他文獻(PDF)里的公式?(更新時間2022.03.01)

我們在寫paper時&#xff0c;經常會遇到在Word里編寫數學公式的問題&#xff0c;其中大多數公式是已經存在的&#xff0c;所以只需要識別、復制、粘貼即可&#xff0c;那么接下來&#xff0c;我就介紹一下“Mathtype”“Mathpix”的方法&#xff0c;分為所需軟件、軟件操作、公…

家里接入某運營商300M寬帶,為何網速還是很慢?(還未裝修房屋的請進來)

&#xff08;請先看置頂博文&#xff09;本博打開方式&#xff0c;請詳讀_liO_Oil的博客-CSDN博客_怎么把androidstudio卸載干凈 引言&#xff1a;家里接入300M的寬帶&#xff0c;但是自我感覺網速不佳&#xff0c;遂結合所學知識&#xff0c;對此問題進行分析、研究和調察&…

(CED)列指針與行指針的聯系與區別

一、列指針&#xff08;豎為列&#xff09; 1、列指針相關定義 列指針&#xff1a;被稱為是指針變量指向二維數組的某個元素 一般使用時會有如下定義&#xff1a; int a[3][4]{1,2,3,4,5,6,7,8,9,10,11,12}; int *p;而上述代碼定義的指針p&#xff0c;一般按照下表方式指向…

C語言(CED)C語言中雙引號和單引號的區別

最簡單的區別&#xff1a; 在字符型變量賦初值時&#xff0c;用單引號&#xff1b;為字符串變量賦初值時用雙引號&#xff01; 具體區別&#xff1a; 1、大小 單引號引起的一個字符&#xff0c;其大小為1個Byte。 雙引號引起的字符串&#xff0c;因為在其結尾需加一個二進…

一、Pytho第一課——Python安裝及配置路徑方法(最詳細小白教程,沒有之一。如若不懂,不是還可以私信嘛!對吧?)

目錄 一、下載軟件 二、安裝 三、編輯器 四、在Pycharm上成功運行Python程序&#xff08;配置Python解釋器&#xff09; 一、下載軟件 官方下載地址&#xff1a;https://www.python.org/downloads/&#xff08;打開似乎很吃力&#xff0c;必要時刻“掛燈”&#xff09; …

二、Python第二課——變量命名規則及字符串變量相關函數

目錄 一、變量命名規則 二、字符串變量及相關函數 1、字符串變量 2、相關函數 最后瑣碎雜物&#xff1a; 1、字符串之間的拼接 2、字符串格式控制&#xff08;制表符和換行&#xff09; 一、變量命名規則 正如其他編程語言一樣&#xff0c;程序離不開聲明變量&#x…

三、Python第三課——Python中數字的用法及編碼原則(Python禪意)

目錄 一、Python中的數字 1、整數 2、浮點數 3、整數、浮點數和字符串的聯系和區別 二、編碼原則 1、為代碼增加注釋 2、Python 禪意 A、編碼精美 B、避繁就簡 C、無簡就繁 D、使用常規方法解決問題 E、先有效、再精巧、逐步升華 一、Python中的數字 編程中&#…

四、Python第四課——Python中列表及其操作(增刪改查)

目錄 一、Python中的列表 1、列表的定義和賦值 2、列表的使用 二、列表的“增刪改查” 1、列表中元素的增加 A、在列表尾添加元素 B、在列表中插入元素 2、列表中“元素的刪除” A、使用del語句刪除元素 B、使用pop()函數刪除元素 C、彈出列表中任何位置元素…

五、Python第五課——Python中組織列表的相關函數

目錄 一、用sort()函數對列表進行永久排序 二、用sorted()函數對列表進行臨時排序 三、用reverse()函數對列表進行列表原始排序的逆序輸出 四、使用len()函數確定列表長度 創建列表后&#xff0c;內部的元素逐漸增多&#xff0c;其排列順序也是無法預測的&#xff0c;因為…

如何正確下載、安裝Codeblocks?

目錄 一、Codeblocks的下載 二、Codeblocks的安裝 三、Codeblocks的運行 相信很多同學在初學C語言時都會選擇一個短小精悍的代碼編輯器&#xff0c;如CodeBlocks&#xff08;不說別的了&#xff0c;直接切入正題&#xff09;。 在2020年&#xff08;今年&#xff09;3月份-…

Python:創建列表,其中包含數字1-1000000,為什么Pycharm控制臺結果顯示不完整?

目錄 一、問題描述&#xff08;尋找解決方法的同學直接看“標題二”&#xff09; 二、解決辦法 一、問題描述&#xff08;尋找解決方法的同學直接看“標題二”&#xff09; 在學習Python過程中遇到一個這樣的問題&#xff0c;也算是一個小BUG吧。題目大意是這樣的&#xff…

六、Python第六課——Python中的for循環及數字列表

目錄 一、Python中的for循環 1、for循環語句的聲明。 2、for循環縮進常見問題 二、數字列表 1、函數range() 2、使用range()函數創建數字列表 3、使用一系列函數處理數字列表&#xff08;統計&#xff09; 4、列表解析&#xff08;生成列表的簡潔方法&#xff09; 一…

七、Python第七課——有關列表的二三事(切片、切片的遍歷和復制)

目錄 一、切片 二、遍歷切片 三、列表的復制 一、切片 此前&#xff0c;我們學習了如何訪問單個列表以及如何處理列表中的所有元素&#xff0c;那么我們如何處理列表中的部分元素呢&#xff1f;這就引出一個概念“切片” 。我們可以把列表看成是面包&#xff0c;“切片”…

八、Python第八課——元組與列表、代碼格式

&#xff08;請先看置頂博文&#xff09;https://blog.csdn.net/GenuineMonster/article/details/104495419 目錄 一、元組的定義 二、元組的遍歷 三、代碼格式 一、元組的定義 1、元組&#xff1a;不可變的列表稱為元組。這個是相對于普通列表而言的&#xff0c;普通列表…