dp之lis//SDNU1040+1221+1292

第一行——咕咕咕。
第二行——我現在才發現我竟然欠了這麼多算法不會(果然講完了不做題就會忘得一乾二淨(自學ing

最長上升子序列:序列不一定唯一,但長度是唯一的
1.我的理解:用dp數組存到第i個數時的最優解,最大即爲最終最優。畢竟dp就是從上一階段的最優解推到先階段最優解。就是以第i個數結尾的最長上升子序列是前i-1個數的最長子序列跟第i個數比較判斷即可。
2.其實如果只讓求最長長度是很簡單的,分暴力+模擬棧(二分兩種,時間複雜度是O(n^2)和O(nlogn)(應該是的(不過模擬棧沒法記錄路徑
3.然而重點是如何記錄路徑(好的我不會

本代碼以SDNU1040爲例

1.偷窺ryc師哥博客後,可得思路
2.攔截系統與上升子序列有關
3.每有一個上升序列的元素,就需要有額外的攔截系統進行攔截
4.若全爲上升序列,則序列有幾個即需要幾個攔截系統
5.其他元素另討論
6.到這裏需要先求出最長上升子序列
7.在序列裏,最長上升子序列之外,分別有前面的大於上升序列首元素,後面的小於上升序列的末尾元素,中間的逆序的元素
8.這些元素,一定可以與上升序列的某個元素組成下降序列,被同一系統攔截
9.一定是上升子序列,因爲非下降子序列(即包含相同元素),因爲相同的可以算一個元素被一個系統攔截。
10.綜上,只需找出最長子序列的長度-1即爲額外所需的導彈攔截系統的個數

//但其實我原本的思路是一次次找最長非上升子序列,標記訪問後再剩下的元素裏找,直至沒有不被訪問過的元素(畢竟oj上數據只有20,不會超過20*20*20)
//我找個時間試試可不可以實現
//就是因爲我沒寫出實現來纔去偷窺了別人的博客

 

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int main()
{
    int a[25];
    int tot = 0;
    int ans = 1;
    int res = 1;
    int dp[25];
    while(~scanf("%d",&a[tot]))
    {
        tot++;
        if(getchar()=='\n')
            break;
    }
    for(int i = 0; i < tot; ++i)
    {
        dp[i] = 1;//截止到第i個數,最長子序列的長度(初始爲1,只有a[i]
        for(int j = 0; j < i; ++j)
        {
            if(a[j]>=a[i]&&dp[i]<dp[j]+1)
            {
                dp[i] = dp[j]+1;
            }
        }
        res = max(res,dp[i]);
    }
    for(int i = 0; i < tot; ++i)
    {
        dp[i] = 1;
        for(int j = 0; j < i; ++j)
        {
            if(a[j]<a[i]&&dp[i]<dp[j]+1)
            {
                dp[i] = dp[j]+1;
            }
        }
        ans = max(ans,dp[i]);
    }
    printf("%d,%d\n",res,ans-1);
    return 0;
}

附上SDNU其他lis

SDNU1292

SDNU1221

發佈了41 篇原創文章 · 獲贊 10 · 訪問量 3497
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章