最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言深入探究動態(tài)規(guī)劃之線性DP

 更新時間:2022年04月12日 14:21:55   作者:小羊努力變強  
線性動態(tài)規(guī)劃,是較常見的一類動態(tài)規(guī)劃問題,其是在線性結構上進行狀態(tài)轉移,這類問題不像背包問題、區(qū)間DP等有固定的模板,線性動態(tài)規(guī)劃的目標函數(shù)為特定變量的線性函數(shù),約束是這些變量的線性不等式或等式,目的是求目標函數(shù)的最大值或最小值

寫在前面

之前講過背包問題,不知道大家忘了嗎,如果忘了可以點這里,這次是線性DP

數(shù)字三角形

在這里插入圖片描述

狀態(tài)表示:f[i,j],到點i,j的最大路徑

狀態(tài)計算:f[i,j] = MAX(f[i-1,j-1]+a[i,j],f[i-1,j]+a[i,j])

在這里插入圖片描述

看圖,以例題為例,將它看成五行五列的三角形,每個點都可以用坐標表示。那么我們可以得知到一個數(shù)的最大路徑要么來自左上,要么來自右上。左上的數(shù)用f[i-1,j-1]表示,右上的數(shù)f[i-1,j]表示,因此我們就有了狀態(tài)轉移公式:

f[i,j] = MAX(f[i-1,j-1]+a[i,j],f[i-1,j]+a[i,j])

所以就有了最終的代碼:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 510, INF = 1e9;

int n;
int a[N][N];
int f[N][N];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            scanf("%d", &a[i][j]);

    for (int i = 0; i <= n; i ++ )
        for (int j = 0; j <= i + 1; j ++ )//注意這里j從0到i+1,因為對于邊界點,它的上一層只有一條路徑通向它
            f[i][j] = -INF;//初始化近似為-∞

    f[1][1] = a[1][1];
    for (int i = 2; i <= n; i ++ )
        for (int j = 1; j <= i; j ++ )
            f[i][j] = max(f[i - 1][j - 1] + a[i][j], f[i - 1][j] + a[i][j]);

    int res = -INF;
    for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);

    printf("%d\n", res);
    return 0;
}

最長上升子序列

在這里插入圖片描述

狀態(tài)表示:f[i]表示從第一個數(shù)字開始算,以w[i]結尾的最大的上升序列。(以w[i]結尾的所有上升序列中屬性為最大值的那一個)

狀態(tài)計算(集合劃分):j∈(0,1,2,…,i-1), 在w[i] > w[j]時,

f[i] = max(f[i], f[j] + 1)。

有一個邊界,若前面沒有比i小的,f[i]為1(自己為結尾)。

最后在找f[i]的最大值。

時間復雜度

O(n2) 狀態(tài)數(shù)(n) * 轉移數(shù)(n)

在這里插入圖片描述

看圖, 首先 f[i]f[i] 的含義是以 w[i]結尾的最長上升子序列的長度

初始值 f[i]=1,i∈[0,n−1],表示自己就是最長上升子序列,長度為 1

接下來考慮狀態(tài)轉移,把前 i−1個數(shù)字中所有滿足條件 w[j]<w[i](因為要求是上升子序列) 的 j 找出來,那么 f[i] 就可以試著更新為以 w[j] 結尾的最長上升子序列的長度 再加上 自己的長度 1,但可能更新完的結果沒有之前更新過的 f[i] 大,最后兩者取一個 max,所以狀態(tài)轉移方程就是 f[i]=max(f[i],f[j]+1)

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int w[N], f[N];

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> w[i];

    int mx = 1;    // 找出所計算的f[i]之中的最大值,邊算邊找
    for (int i = 0; i < n; i++) {
        f[i] = 1;    // 設f[i]默認為1,找不到前面數(shù)字小于自己的時候就為1
        for (int j = 0; j < i; j++) {
            if (w[i] > w[j]) f[i] = max(f[i], f[j] + 1);    // 前一個小于自己的數(shù)結尾的最大上升子序列加上自己,即+1
        }
        mx = max(mx, f[i]);
    }

    cout << mx << endl;
    return 0;
}

最長上升子序列 II

在這里插入圖片描述

會發(fā)現(xiàn)II的數(shù)據(jù)范圍變了,那我們就得做優(yōu)化,怎么優(yōu)化呢?

狀態(tài)表示:f[i]表示長度為i的最長上升子序列,末尾最小的數(shù)字。(長度為i的最長上升子序列所有結尾中,結尾最小min的) 即長度為i的子序列末尾最小元素是什么。

狀態(tài)計算:對于每一個w[i], 如果大于f[cnt-1] (下標從0開始,cnt長度的最長上升子序列,末尾最小的數(shù)字),那就cnt+1,使得最長上升序列長度+1,當前末尾最小元素為w[i]。 若w[i]小于等于f[cnt-1],說明不會更新當前的長度,但之前末尾的最小元素要發(fā)生變化,找到第一個 大于或等于 (這里不能是大于) w[i],更新以那時候末尾的最小元素。

f[i]一定以一個單調遞增的數(shù)組,所以可以用二分法來找第一個大于或等于w[i]的數(shù)字。

時間復雜度

O(nlogn)狀態(tài)數(shù)(n) * 轉移數(shù)(logn)

#include <iostream>

using namespace std;

const int N = 1010;
int n, cnt;
int w[N], f[N];

int main() {
    cin >> n;
    for (int i = 0 ; i < n; i++) cin >> w[i];

    f[cnt++] = w[0];
    for (int i = 1; i < n; i++) {
        if (w[i] > f[cnt-1]) f[cnt++] = w[i];
        else {
            int l = 0, r = cnt - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (f[mid] >= w[i]) r = mid;
                else l = mid + 1;
            }
            f[r] = w[i];
        }
    }
    cout << cnt << endl;
    return 0;
}

最長公共子序列

在這里插入圖片描述

在這里插入圖片描述

集合表示:f[i][j]表示a的前i個字母,和b的前j個字母的最長公共子序列長度

集合劃分:以a[i],b[j]是否包含在子序列當中為依據(jù),因此可以分成四類:

  • ①a[i]不在,b[j]不在

max=f[i−1][j−1]

  • ②a[i]a[i]不在,b[j]b[j]在

看似是max=f[i−1][j] , 實際上無法用f[i−1][j]表示,因為f[i−1][j]表示的是在a的前i-1個字母中出現(xiàn),并且在b的前j個字母中出現(xiàn),此時b[j]不一定出現(xiàn),這與條件不完全相等,條件給定是a[i]一定不在子序列中,b[j]一定在子序列當中,但仍可以用f[i−1][j]來表示,原因就在于條件給定的情況被包含在f[i−1][j]中,即條件的情況是f[i−1][j]的子集,而求的是max,所以對結果不影響。

例如:要求a,b,c的最大值可以這樣求:max(max(a,b),max(b,c))雖然b被重復使用,但仍能求出max,求max只要保證不漏即可。

  • ③a[i],b[j]不在 原理同②
  • ④a[i]在,b[j]在 max=f[i−1][j−1]+1

實際上,在計算時,①包含在②和③的情況中,所以①不用考慮

#include <iostream>

using namespace std;

const int N = 1010;

int n , m;
char a[N] , b[N];
int f[N][N];
int main()
{
    cin >> n >> m;
    cin >> a + 1 >> b + 1;

    for(int i = 1 ; i <= n ; i++)
        for(int j = 1 ; j <= m ; j++)
            {
                f[i][j] = max(f[i - 1][j] , f[i][j - 1]);//2和3的情況一定存在,所以可以無條件優(yōu)先判斷
                if(a[i] == b[j]) f[i][j] = max(f[i][j] , f[i - 1][j - 1] + 1);
            }                                                       

    cout << f[n][m] << endl;
    return 0;
}

到此這篇關于C語言深入探究動態(tài)規(guī)劃之線性DP的文章就介紹到這了,更多相關C語言 線性DP內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 詳解C語言中strcpy函數(shù)與memcpy函數(shù)的區(qū)別與實現(xiàn)

    詳解C語言中strcpy函數(shù)與memcpy函數(shù)的區(qū)別與實現(xiàn)

    這篇文章主要介紹了C語言中字符串拷貝函數(shù)(strcpy)與內存拷貝函數(shù)(memcpy)的不同及內存拷貝函數(shù)的模擬實現(xiàn),感興趣的小伙伴可以跟隨小編一起學習一下
    2022-12-12
  • C++利用鏈表模板類實現(xiàn)簡易隊列

    C++利用鏈表模板類實現(xiàn)簡易隊列

    這篇文章主要為大家詳細介紹了C++利用鏈表模板類實現(xiàn)一個簡易隊列,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng)

    C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C++項目開發(fā)實現(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 詳解C++中存儲類的使用

    詳解C++中存儲類的使用

    存儲類定義?C++?程序中變量/函數(shù)的范圍(可見性)和生命周期。這些說明符放置在它們所修飾的類型之前。auto、register、static、extern和mutable是C++程序中常用的存儲類,本文主要介紹了它們的使用方法,需要的可以參考一下
    2022-12-12
  • OpenCV計算輪廓長度/周長和面積

    OpenCV計算輪廓長度/周長和面積

    這篇文章主要為大家詳細介紹了OpenCV計算輪廓長度/周長和面積,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C語言深入探究斐波那契數(shù)列

    C語言深入探究斐波那契數(shù)列

    斐波那契數(shù)一般指斐波那契數(shù)列。 斐波那契數(shù)列(Fibonacci sequence),又稱黃金分割數(shù)列,因數(shù)學家萊昂納多·斐波那契(Leonardo Fibonacci)以兔子繁殖為例子而引入,故又稱為兔子數(shù)列
    2022-05-05
  • C/C++中獲取數(shù)組長度的方法示例

    C/C++中獲取數(shù)組長度的方法示例

    這篇文章主要介紹了C/C++中獲取數(shù)組長度的方法,很實用的一種方法,需要的朋友可以參考下
    2014-08-08
  • 判斷機器大小端的兩種實現(xiàn)方法

    判斷機器大小端的兩種實現(xiàn)方法

    第一種方法,思路:利用指針的強制類型轉換。第二種方法,思路:利用共用體所有數(shù)據(jù)都從同一地址開始存儲。
    2013-03-03
  • C數(shù)據(jù)結構之單鏈表詳細示例分析

    C數(shù)據(jù)結構之單鏈表詳細示例分析

    以下是對C語言中的單鏈表進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • 淺析C++中模板的那點事

    淺析C++中模板的那點事

    C++中的模板可分為函數(shù)模板和類模板,而把函數(shù)模板的具體化稱為模板函數(shù),把類模板的具體化成為模板類。下面讓我們分別看看什么是函數(shù)模板和類模板吧
    2013-09-09

最新評論

平谷区| 梁河县| 平南县| 西华县| 灵台县| 邵阳县| 深水埗区| 崇义县| 台南市| 青河县| 玛纳斯县| 通渭县| 屏东县| 黎平县| 苗栗县| 祥云县| 衡东县| 泸溪县| 大安市| 新营市| 自治县| 莱州市| 九台市| 内江市| 天等县| 新乐市| 博湖县| 开江县| 上杭县| 高清| 远安县| 永嘉县| 崇信县| 柘城县| 西昌市| 定兴县| 阿拉尔市| 湘乡市| 冕宁县| 太保市| 正定县|