淺談區(qū)間動態(tài)規(guī)劃

圍繞幾道題說起哩盲。。石子歸并狈醉、涂色廉油、括號序列

啥是區(qū)間動態(tài)規(guī)劃呢,我覺得似乎是指在一段區(qū)間上的dp苗傅,通過枚舉左右子區(qū)間來求出解抒线。

那么問題來了,如何去枚舉左右子區(qū)間呢渣慕?

一般來說都是循環(huán)一個變量len嘶炭,表示區(qū)間長度,然后循環(huán)左區(qū)間從開始到結(jié)尾摇庙,一般來說是1~n旱物。

對于區(qū)間dp的話,我大致理解就是先求出小區(qū)間(部分)最優(yōu)解卫袒,然后一個又一個小區(qū)間合并成稍微大點的大區(qū)間宵呛,最后合成答案——即總區(qū)間。

所以代碼就這玩意:

for(int len=1;len<=n;len++)
{
    for(int l=1,r;(r=l+len)<=n;l++)
    {
        //do something
        for(int k=l;k<r;k++)
        {
            //update dp array,such as'min(dp[l][r],dp[l][i]+dp[i+1][r])'
        }
    }
}

所以就是這樣咯夕凝,循環(huán)一個長度宝穗,然后枚舉區(qū)間户秤。

區(qū)間的話一定要注意是l<=k<r,不然的話[i+1][r]直接6了逮矛。鸡号。。

好像须鼎。鲸伴。。區(qū)間dp就這些內(nèi)容了吧晋控,哦對了還有平行四邊形優(yōu)化汞窗!

普通的區(qū)間dp的時間復(fù)雜度大約是O(n^3),從三個嵌套的for就能看出來赡译。

不過有一些區(qū)間dp可以優(yōu)化成O(n^2)仲吏,要用一個叫做“四邊形不等式”的東西進(jìn)行優(yōu)化。

大致思想就是保存枚舉的k中最優(yōu)子區(qū)間蝌焚,每次可以將枚舉k時的時間復(fù)雜度去掉裹唆,所以就只剩下了長度與左區(qū)間的枚舉。

四邊形不等式優(yōu)化

下面就是三道入門題只洒。许帐。。


//石子歸并
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
char in[1000];
int dp[1000][1000],n,w[1000],sum[1000];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]);
        sum[i]=sum[i-1]+w[i];//由于合并的是一個區(qū)間红碑,所以記錄一下前綴和
    }
    for(int len=1;len<=n;len++)//循環(huán)長度
    {
        for(int l=1,r;(r=l+len)<=n;l++)
        {
            dp[l][r]=0x3fffffff;//初始化為INF
            for(int i=l;i<r;i++)//枚舉中點
                dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r]+sum[r]-sum[l-1]);//判斷區(qū)間l,r分割成兩個小區(qū)間后是否更優(yōu)
        }
    }
    printf("%d\n",dp[1][n]);//答案
}

//bzoj1260涂色
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
char in[1000];
int dp[1000][1000];
int main()
{
    scanf("%s",in+1);//方便下面dp
    int n=strlen(in+1);
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dp[i][j]=i==j?1:0x3fffffff;//對于一個點的涂色次數(shù)舞吭,只能是1次
    for(int len=1;len<=n;len++)//循環(huán)長度
    {
        for(int l=1,r;(r=l+len)<=n;l++)//生成左右區(qū)間
        {
            if(in[l]==in[r])//如果相等那么就可以如下這么轉(zhuǎn)移咯
            {
                if(len==1)dp[l][r]=1;//如果區(qū)間長度為1,也就是說l,r是相鄰的兩個格子析珊,所以只能一筆涂上
                else dp[l][r]=min(dp[l+1][r-1]+1,min(dp[l][r-1],dp[l+1][r]));
                /*
                    否則的話說明可以從區(qū)間l,r中進(jìn)行轉(zhuǎn)移。
                    判斷dp[l][r]所包含的三個子區(qū)間
                    然后就是dp[l+1][r]跟dp[l][r-1]了蔑穴。
                    先把最右端/最左端為起點一筆涂到另一頭忠寻,應(yīng)該是這意思吧?
                */
            }
            else//否則的話只能將區(qū)間l,r分割成兩個小區(qū)間然后min咯
                for(int i=l;i<r;i++)
                    dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r]);
        }
    }
    printf("%d\n",dp[1][n]);//答案
}

//tyvj P1193 括號序列
/*
    至于為什么這個dp是對的存和,小談一下我的個人理解奕剃。
    由于區(qū)間長度len是從小到的枚舉的,所以每一輪都是從很小的單位區(qū)間開始更新捐腿,似乎可以看作bfs(霧)纵朋?
    因為len是由小到大進(jìn)行枚舉,所以每一次min的時候都是從將已經(jīng)判斷好的子區(qū)間進(jìn)行min茄袖。
    或許用滾雪球形容會好點操软?從一個小區(qū)間慢慢滾成了一個大區(qū)間?
    以上就是我對于初級區(qū)間dp的理解宪祥。聂薪。家乘。
*/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
char in[1000];
int dp[1000][1000],n;
bool test(char a,char b)//判斷a,b是否匹配
{
    if(a=='(')return b==')';
    if(a=='[')return b==']';
    if(a=='<')return b=='>';
    if(a=='{')return b=='}';
    return 0;
}
int main()
{
    /*
        dp[i][i]=1 若是單個括號的話只能是添加所對應(yīng)的括號完成匹配,所以為1
        dp[l][r]:區(qū)間l,r的最小添加括號數(shù)量
        dp[l][r]=min{n,dp[l+1][r-1](match(s[l],s[r]),dp[l][k]+dp[k+1][r]|l<=k<r}
    */
    gets(in+1);//為了能夠順手的寫代碼藏澳,所以下標(biāo)從1開始
    n=strlen(in+1);
    while(in[n]=='\n'||in[n]=='\r')n--;
    //不知道為啥gets會莫名其妙的讀入一個換行/回車仁锯,所以第一次就WA了。翔悠。业崖。所以加上這個while判一下是否有換行,不過似乎最多就循環(huán)一次蓄愁?
    for(int i=1;i<=n;i++)dp[i][i]=1;
    for(int len=1;len<=n;len++)
    {
        for(int l=1,r;(r=l+len)<=n;l++)
        {
            dp[l][r]=r-l+1;//邊界双炕,對于區(qū)間l,r一共有r-l+1個括號,所以最壞情況下需要添加r-l+1個括號涝登,不過似乎寫成n也能A掉雄家?好吧寫成dp[l][r]=n會快點。胀滚。趟济。畢竟避免了加減法運算
            if(test(in[l],in[r]))//如果左右兩端匹配,那么就可以進(jìn)行一次轉(zhuǎn)移
                dp[l][r]=min(dp[l][r],dp[l+1][r-1]);//如果當(dāng)前區(qū)間左右都是匹配的括號的話咽笼,狀態(tài)轉(zhuǎn)移為dp[l+1][r-1]顷编,也就是說轉(zhuǎn)移到去掉括號后的序列
            for(int i=l;i<r;i++)//枚舉區(qū)間l,r中的所有區(qū)間
                dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r]);
        }
    }
    printf("%d\n",dp[1][n]);//最后的結(jié)果就是dp[1][n]
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市剑刑,隨后出現(xiàn)的幾起案子媳纬,更是在濱河造成了極大的恐慌,老刑警劉巖施掏,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钮惠,死亡現(xiàn)場離奇詭異,居然都是意外死亡七芭,警方通過查閱死者的電腦和手機素挽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狸驳,“玉大人预明,你說我怎么就攤上這事“夜浚” “怎么了撰糠?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辩昆。 經(jīng)常有香客問我阅酪,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任遮斥,我火速辦了婚禮峦失,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘术吗。我一直安慰自己尉辑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布较屿。 她就那樣靜靜地躺著隧魄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隘蝎。 梳的紋絲不亂的頭發(fā)上购啄,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音嘱么,去河邊找鬼狮含。 笑死,一個胖子當(dāng)著我的面吹牛曼振,可吹牛的內(nèi)容都是我干的几迄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼冰评,長吁一口氣:“原來是場噩夢啊……” “哼映胁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起甲雅,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤解孙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后抛人,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弛姜,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年妖枚,在試婚紗的時候發(fā)現(xiàn)自己被綠了娱据。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡盅惜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忌穿,到底是詐尸還是另有隱情抒寂,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布掠剑,位于F島的核電站屈芜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜井佑,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一属铁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躬翁,春花似錦焦蘑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宁舰,卻和暖如春拼卵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蛮艰。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工腋腮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壤蚜。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓即寡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仍律。 傳聞我的和親對象是個殘疾皇子嘿悬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

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

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,748評論 0 33
  • 動態(tài)規(guī)劃(Dynamic Programming) 本文包括: 動態(tài)規(guī)劃定義 狀態(tài)轉(zhuǎn)移方程 動態(tài)規(guī)劃算法步驟 最長...
    廖少少閱讀 3,293評論 0 18
  • 歸去來兮水泉。 1.1 說明 本篇為《挑戰(zhàn)程序設(shè)計競賽(第2版)》[http://www.ituring.com.cn...
    尤汐Yogy閱讀 14,354評論 0 160
  • 以前在linux下看源碼一直習(xí)慣用source insight善涨,然而最近發(fā)現(xiàn)sublime text的插件好多好強...
    少閣主_enfj閱讀 9,087評論 1 2
  • 在聽完陳奕迅的歌 又換到了twins 時間一點一點 歌聲輾轉(zhuǎn)離合 一個一個字符音符 像極了奔跑的雪花 在雪地翻滾打...
    言由衷閱讀 243評論 0 0