三維DP--POJ1390--Blocks
阿新 • • 發佈:2018-03-03
using stdin mes gin ... 模型 數學模型 數字 block
題意介紹
初看這道題,想了想沒頭緒,感覺又要被虐了,按照《算法基礎》郭老師的講解,勉強接受了這個奇怪的狀態轉移方程,但是還是感覺很吃力,照著視頻寫了一遍之後,又去網上看了看別人的代碼,我的天哪,比郭老師的簡潔多了!然後自己獨立寫了一遍,終於感覺好多了。原本感覺無從下手的難題,最後自己能夠獨立寫出來,這種感覺真好,不過,能寫出來不代表下一道狀態轉移方程如此之怪的題目我也能寫,還是要多學習,多思考~
最後想說的是,視頻最後郭老師喝完水扔瓶子是真的騷
言歸正傳:
當遇到動歸問題,我們的數學模型推不下去時,這道題其實給我們指明了方向:增加參數(維度),例如這道題就是三維動歸
初看這道題首先想到的估計大家都差不多(大神除外),那就是用前n-1個數字序列的結果算出前n個數字序列的結果,很快發現這樣做是不行的,於是陷入了泥漿...終於想到了,我們可以用i--j-1之間的數字序列的結果去算推i--j之間的數字序列的結果,試了試發現好像也不行,於是陷入了泥漿...
dp[L][R][K];
其中K代表R右側和R顏色一樣的那一小排方塊的數量,這樣子dp[1][n][0]就是最終解,轉態轉移方程就也能寫出來了(別問我怎麽想到的,我也沒想到):
1.最右側單獨消除,dp[L][R][K]=dp[L][R-1][0]+(len[R]+k)^2;
2.最右側的,和區間段(L,R)中的某一塊進行消除(要顏色一樣能消除),假設iL< = p < R滿足條件,則dp[L][R][k]=dp[L][p][k+len[R]]+dp[p+1][R-1][0]。
算出第一種的解,枚舉所有第二種情況的解,取上面之中最大的結果即可,記得要記憶化搜索。
代碼:
#include<iostream> #include<cstring> using namespace std; const int maxn=200+50; int color[maxn],len[maxn]; int ans[maxn][maxn][maxn]; int dp(int l,int r,int k){ int result,temp; if(ans[l][r][k]>0) return ans[l][r][k]; result=k+len[r]; result*=result; if(l==r){ ans[l][r][k]=result;return result; } result+=dp(l,r-1,0); for(int i=r-1;i>=l;i--){ if(color[i]!=color[r]) continue; temp=dp(l,i,len[r]+k)+dp(i+1,r-1,0); if(temp<result) continue; result=temp; } ans[l][r][k]=result; return result; } int main(){ // freopen("in.txt","r",stdin); int n,m,col,cnt; cin>>n; for(int i=0;i<n;i++){ cin>>m; cin>>color[1]; len[1]=1; cnt=1; for(int l=2;l<=m;l++){ cin>>col; if(col==color[cnt]) len[cnt]++; else{ ++cnt; color[cnt]=col; len[cnt]=1; } } memset(ans,0,sizeof(ans)); printf("Case %d: %d\n",i+1,dp(1,cnt,0)); } }
三維DP--POJ1390--Blocks