1. 程式人生 > 其它 >區間dp學習筆記

區間dp學習筆記

退役人回來了/fad

回來學習dp(

於是先好好學習一下區間dp吧qwq

一.什麼是區間dp

大家都知道什麼是dp吧,dp有三部曲:定義狀態,狀態轉移方程,邊界條件。

那區間dp呢?差不多,只是它有一個範圍限制,就是說它的操作只可以在這個範圍內進行。

所以我們區間dp的迴圈有三個維度:區間長度,左端點(有了左端點和區間長度右端點就出來了對不對),斷點。它們分別對應這區間dp的三個主體:階段。狀態,決策點。

乾巴巴的東西說多了沒用,我們直接看例題!

區間dp模板詳解

找了一道模板:ybt1274.合併石子

就是純模板題,要注意的就是合併操作的dp陣列需要做初始化,因為是求最小值。

直接上核心程式碼qwq?

注意:要加上的得分就是兩堆石子的數量總和,建議字首和預處理這種區間和問題。


memset(dp,0x3f,sizeof(dp));
	for(int i=0;i<=n;i++)dp[i][i]=0;
	
	for(int len=2;len<=n;len++){//因為預處理過了區間長度為1的情況,所以len要從2開始qaq
		for(int i=1;i+len-1<=n;i++){
			int j=i+len-1;
			for(int k=i;k<=j-1;k++){
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]);
			}
		}
	}

既然說到有區間限制,我們就順便說說沒用區間限制的時候。

那就是這個P1090.合併果子

於是可以想到用貪心結合棧解決了qeq

以下是核心程式碼:


while(pq.size()>1){
		x=pq.top();
		pq.pop();
		y=pq.top();
		pq.pop();
		ans+=(x+y);
		pq.push(x+y);
	}

三.解題報告

這個絕對會更新(

1.P1880.石子合併

先來一個板子題的強化版。

和板子題不太一樣的點有兩個:這是一個環;要求最大和最小同時維護。

第二個簡單,第一個有難度。

於是我們來拆環為鏈

因為對於這個環,我們隨便選一個點把它拆開,就有 \(n\)

種方式。

而我們把題目中給的排列方式double一下,這個鏈就包含了所有拆分方式!

於是就很簡單了~~

核心程式碼:


for(int i=1;i<=n;i++){
        cin>>a[i];
        a[n+i]=a[i];
    }
    n*=2;
    memset(minn,0x3f,sizeof(minn));
    minn[0][0]=maxn[0][0]=0;
    for(int i=1;i<=n;i++){
        s[i]=s[i-1]+a[i];
        minn[i][i]=maxn[i][i]=0;
    }

    for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            for(int k=i;k<=j-1;k++){
                minn[i][j]=min(minn[i][j],minn[i][k]+minn[k+1][j]+s[j]-s[i-1]);
                maxn[i][j]=max(maxn[i][j],maxn[i][k]+maxn[k+1][j]+s[j]-s[i-1]);
            }
        }
    }

輸出操作被和諧掉了(

建議自行思考輸出什麼qeq

2.P1063.能量項鍊

綠就綠在這個環了,而環的操作已經講了,直接和諧掉程式碼(bushi

3.P3146.[USACO16OPEN]248 G

非常好,這是一道和模板題基本上沒有差別的題(

程式碼被lk鴿鴿吃掉了。

4.P4170 [CQOI2007]塗色

5.P2858 [USACO06FEB]Treats for the Cows G/S

6.P1622 釋放囚犯

這個非常重要,lk鴿鴿明天再寫(“鈦晚了”

求監督lk鴿鴿不要咕咕咕