日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

LQ训练营(C++)学习笔记_常见动态规划模型

發布時間:2023/12/15 c/c++ 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LQ训练营(C++)学习笔记_常见动态规划模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

常見動態規劃模型

  • 六、常見動態規劃模型
    • 1、最大字段和
      • 1.1 概念描述
      • 1.2動態規劃算法分析
      • 1.3 代碼實現
    • 2、最長上升子序列(LIS)
      • 2.1 概念描述
      • 2.2 算法分析
      • 2.3 代碼實現
    • 3、最長公共子序列
      • 3.1 概念描述
      • 3.2 算法分析
      • 3.3 代碼實現

六、常見動態規劃模型

1、最大字段和

1.1 概念描述

給定一個由數字組成的序列,其中連續的一段子序列稱為一個子段,子段中的所有數之和稱為子段和,這里只考慮非空子段,即至少包含一個元素的子段,一個序列中子段和最大的子段的子段和,為最大子段和。

1.2動態規劃算法分析

對于全部是非正數的序列,最大子段和為其中元素的最大值。
對于有正數的序列,考慮以每一個點為結尾的最大子段和,這個子段一定滿足其前綴和均非負,因為如果有一個前綴是負的,那么減掉這個前綴對于這個點一定更優,并且這個子段要盡量往前延伸。
我們可以只用一次掃描,記錄目前統計的sum以及答案ans。當sum加上當前位置這個數還是正數的時候就繼續累加sum,否則就將sum置為0 。這樣就舍掉了所有前綴是負數的情況,并且保證了這個子段盡可能的長,也就是說掃描中記錄的sum就是以每一個點為結尾的最大子段和,每一次如果sum比ans大就可以更新ans 。最后ans就是整體的最大子段和。

1.3 代碼實現

#include<iostream> #include<algorithm> using namespace std; const int inf = 0x7fffffff; int num[101]; int main(){int N;cin>>N;//讀入N和N個變量for(int i=0;i<N;i++){cin>>num[i];}int ans=-inf;//聲明ans并初始化for(int i=0;i<N;i++){//遍歷數組有沒有正數,并找出最大值ans=max(ans,num[i])}if(ans<=0){//若ans非負,輸出cout<<ans<<endl;}else{int sum=0;//聲明sum,并初始化為0for(int i=0;i<N;i++){if(sum+num[i]<0){//如果加上后為負數,就舍棄這一段重新開始sum=0;}else{//否則將sum加上num[i]sum+=0;}ans=max(ans,sum);//看看是否需要更新}}cout<<ans<<endl;return 0; }

2、最長上升子序列(LIS)

2.1 概念描述

在原序列取任意多項,在不改變他們原來數列的先后順序,得到的序列稱為原序列的子序列。最長上升子序列,就是給定的序列的最長的,數值從低到高排列的的子序列。

2.2 算法分析

所以我們需要描述一下這道題,很顯然這題用一維就可以去描述了,而這題的階段就是以第i項作為結尾端點的上升子序列(即dp[i]),而這題的狀態就是第i個位置的最長上升子序列的長度,決策的話就是第i個位置是否加入要計算的最長上升子序列(a[j]<a[i],j<i這樣的情況才能加入),所以我們就可以推出來他的轉移方程:,其實這就是一個帶有最優子結構的遞推轉移方程,如果滿足加入最長上升子序列的條件后我們并不一定非得必須加入(因為之前還有可能有以他為結尾的更長的上升子序列)。需要注意的一點是我們需要用兩層for循環來找出他的最長上升子序列長度(因為最長上升子序列不是唯一的,所以每一個起點都要去試一下)。

這是遞推打表之后得到的模擬表:

2.3 代碼實現

#include<iostream> #include<cstring> using namespace std; int dp[101],a[101],n; int LIS(){int ans=0;for(int i=1;i<=n;i++){dp[i]=1;for(int j=1;j<i;j++){if(a[j]<a[i]){dp[i]=max(dp[i],dp[j]+1);//狀態轉移方程}}ans=max(ans,dp[i]);//每次內層循環結束后更新ans的值}return ans; } int main(){cin>>n;for(int i;i<=n;i++){cin>>a[i];}cout<<LIS()<<endl;return 0; }

3、最長公共子序列

3.1 概念描述

給定兩個序列S1和S2,求兩者公共子序列S3的最長長度。

3.2 算法分析

這個題目可以按照序列的長度來劃分狀態,也就是S1的前i個字符和S2的前j個字符的最長公共子序列長度,記為lcs[i][j].
如果S1的第i項和S2 的第j項相同,那么S1[i]與S2[j]作為公共子序列的末尾,則
lcs[i][j]=lcs[i-1][j-1]+1
也可以不讓S1[i]與S2[j]作為公共子序列的末尾,則
lcs[i][j]=max(lcs[i][j-1],lcs[i-1][j])

不難證明:

max(lcs[i][j-1],Ics[i-1][j])< Ics[i-1][j-1]+1

那么轉移方程是:

舉一個例子,兩個序列 S1? = abcfbc和S2? = abfcab,根據轉移方程可以得出 lcs[i][j]

3.3 代碼實現

#include <iostream> #include <cstring> #include <string> using namespace std; int dp[110][110];//定義一個輔助數組 int main() {string a, b;memset(dp, 0, sizeof(dp));//將dp數組初始化cin >> a >> b;//輸入兩個字符串a、bint lena = a.size();//計算字符串a、b的長度int lenb = b.size();for (int i = 1; i <= lena; i++){for (int j = 1; j <= lenb; j++){if (a[i - 1] == b[j - 1]){dp[i][j] = dp[i - 1][j - 1] + 1;//dp[i][j]代表a字符串的前i個字符串組成的子串和b字符串的前j個字符串組成的子串LCS}else{dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);}}}cout << dp[lena][lenb] << endl;return 0; }

總結

以上是生活随笔為你收集整理的LQ训练营(C++)学习笔记_常见动态规划模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。