ybt-1306:最長(zhǎng)公共上升子序列

這題有點(diǎn)復(fù)雜的主守,卡了很久禀倔。在做這題以前榄融,首先回顧一下最長(zhǎng)公共子序列(LCS)的求法:
https://blog.csdn.net/wangdan11111/article/details/41321277
上述第二種方法其實(shí)用的是記憶化搜索。

下面來討論怎么求最長(zhǎng)公共上長(zhǎng)子序列(LCIS)

令兩個(gè)數(shù)列保存于a[]和b[]救湖,長(zhǎng)度分別為n和m

  • 首先愧杯,定義狀態(tài)d[i][j]:以a數(shù)組的前i個(gè)元素,b數(shù)組的前j個(gè)元素并且以b[j]為結(jié)尾的LCIS的長(zhǎng)度鞋既。

  • 那么力九,來看看遞推關(guān)系是怎么樣的:
    當(dāng) a[i] != b[j] 時(shí)涛救, d[i][j] = d[i-1][j]; 因?yàn)?d[i][j] 是以 b[j] 為結(jié)尾的LCIS畏邢,如果 d[i][j] > 0 那么就說明 a[1] .... a[i] 中必然有一個(gè)元素 a[k] 等于 b[j]。因?yàn)?a[k] != a[i]检吆,那么 a[i] 對(duì) d[i][j] 沒有貢獻(xiàn)舒萎,于是我們不考慮它照樣能得出 d[i][j] 的最優(yōu)值。所以在 a[i] != b[j] 的情況下必然有 d[i][j] = d[i-1][j]蹭沛。這一點(diǎn)參考LCS的處理方法臂寝。

     d[i][j]=d[i-1][j];
    

    當(dāng) a[i] == b[j] 時(shí), 這個(gè)等于起碼保證了長(zhǎng)度為1的LCIS摊灭。然后我們還需要去找一個(gè)最長(zhǎng)的且能讓b[j]接在其末尾的LCIS咆贬。之前最長(zhǎng)的LCIS在哪呢?首先我們要去找的d數(shù)組的第一維必然是i-1帚呼。因?yàn)閕已經(jīng)拿去和b[j]配對(duì)去了掏缎,不能用了。第二維需要枚舉 b[1] ... b[j-1]了煤杀,因?yàn)槟悴恢肋@里面哪個(gè)最長(zhǎng)且哪個(gè)小于 b[j]眷蜈。
    所以狀態(tài)轉(zhuǎn)移方程:

    d[i][j]=max(d[i-1][k]) + 1; (1<= k <= j-1 且 b[k]<b[j])
    
  • 最后要求的就是d[n][1],d[n][2],...,d[n][m]的最大值,然后用一個(gè)pre[]記錄前一個(gè)位置沈自,遞歸輸出其中一個(gè)滿足要求的子序列即可酌儒,代碼如下:

//不能在最長(zhǎng)公共子序列中求最長(zhǎng)上升子序列,反例如下:
//1 6 3 4 8 和 1 3 6 4 8
//最長(zhǎng)公共子序列:1 6 4 8
//最長(zhǎng)公共上升子序列:1 3 4 8,不在上述求出的序列中 
#define debug(x) std::cerr<<#x<<" = "<<(x)<<std::endl;
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int n,m,a[501],b[501],d[501][501],pre[501];
void print(int x){
    if (x==0) return;
    print(pre[x]);
    printf("%d ",b[x]);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%d",a+i);
    scanf("%d",&m);
    for (int i=1;i<=m;++i) scanf("%d",b+i);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j){
            d[i][j]=d[i-1][j];
            if (a[i]==b[j]){
                int maxn=0,ind=0;
                for (int k=1;k<=j-1;++k)
                    if (d[i-1][k]>maxn && b[k]<b[j]){
                        maxn=d[i-1][k];
                        ind=k;
                    }
                d[i][j]=maxn+1;
                pre[j]=ind;
            }
        }
    int ans=0,ind=0;
    for (int j=1;j<=m;++j)
        if (ans<d[n][j]){
            ans=d[n][j];
            ind=j;
        }
    cout<<ans<<endl;
    print(ind);
    cout<<endl;
    return 0;
}

不難看到枯途,這是一個(gè)時(shí)間復(fù)雜度為O(n^3)的DP忌怎,離平方還有一段距離。

但是酪夷,這個(gè)算法最關(guān)鍵的是榴啸,如果按照一個(gè)合理的遞推順序,max(d[i-1][k])的值我們可以在之前訪問 d[i][k] 的時(shí)候通過維護(hù)更新一個(gè)max變量得到晚岭。怎么得到呢插掂?首先遞推的順序必須是狀態(tài)的第一維在外層循環(huán),第二維在內(nèi)層循環(huán)。也就是算好了 d[1][m] 再去算 d[2][1]辅甥。 如果按照這個(gè)遞推順序我們可以在每次外層循環(huán)的開始加上令一個(gè)max變量為0,然后開始內(nèi)層循環(huán)燎竖。當(dāng)a[i]>b[j]的時(shí)候令max = d[i-1][j]璃弄。如果循環(huán)到了a[i] == b[j]的時(shí)候,則令 d[i][j] = max+1构回。 最后答案是 d[n][1] ... d[n][m]的最大值夏块。
上述分析參考了:https://www.cnblogs.com/wd-one/p/4470844.html
里面還有一個(gè)例子,可以幫助理解纤掸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脐供,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子借跪,更是在濱河造成了極大的恐慌政己,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掏愁,死亡現(xiàn)場(chǎng)離奇詭異歇由,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)果港,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門沦泌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辛掠,你說我怎么就攤上這事谢谦。” “怎么了萝衩?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵回挽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我欠气,道長(zhǎng)厅各,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任预柒,我火速辦了婚禮队塘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宜鸯。我一直安慰自己憔古,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布淋袖。 她就那樣靜靜地躺著鸿市,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焰情,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天陌凳,我揣著相機(jī)與錄音,去河邊找鬼内舟。 笑死合敦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的验游。 我是一名探鬼主播充岛,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼耕蝉!你這毒婦竟也來了崔梗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤垒在,失蹤者是張志新(化名)和其女友劉穎蒜魄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爪膊,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡权悟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了推盛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峦阁。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖耘成,靈堂內(nèi)的尸體忽然破棺而出榔昔,到底是詐尸還是另有隱情,我是刑警寧澤瘪菌,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布撒会,位于F島的核電站,受9級(jí)特大地震影響师妙,放射性物質(zhì)發(fā)生泄漏诵肛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一默穴、第九天 我趴在偏房一處隱蔽的房頂上張望怔檩。 院中可真熱鬧,春花似錦蓄诽、人聲如沸薛训。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乙埃。三九已至闸英,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間介袜,已是汗流浹背甫何。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留米酬,地道東北人沛豌。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赃额,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叫确,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容