poj上的dp專題

更新中...node

http://poj.org/problem?id=1037ubuntu

dp[i][j][0]表示序列長度爲i,以j開始而且前兩位降低的合法序列數目;數組

dp[i][j][1]表示序列長度爲i, 以j開始而且前兩位上升的合法序列數目;優化

因而咱們能夠獲得遞推方程式:dp[i][j][0] += dp[i-1][k][1] ( 1 <= k < j ), dp[i][j][1] += dp[i-1][k][0] ( k <= j <= i), 而後咱們就能夠從第一位開始枚舉了。spa

http://paste.ubuntu.com/6941791/code

 

http://poj.org/problem?id=1887blog

題目看了半天,就是求最長降低子序列,nlog(n)作法,不過莫名其妙的wa了好屢次,不能多說。。遞歸

http://paste.ubuntu.com/6952643/字符串

 

http://poj.org/problem?id=1157get

dp[i][j]表示前i束花放到前j個花瓶中所得到的最大價值,因而有dp[i][j] = max(dp[i-1][j-1] + value[i][j], dp[i][j-1]) (i <= j <= m)(這是由於對於第i束花,能夠選擇放在第j個花瓶中,也能夠選擇放在前j - 1個花瓶中)

稍微要注意一下的就是初始化的問題了,因爲是有序的放,所以dp[i][i] = dp[i-1][i-1] + value[i][i](1 <= i <= n)

http://paste.ubuntu.com/6953048/

 

http://poj.org/problem?id=1088

這道題很容易就看出要用記憶化搜索,若是周圍的點的高度比當前的點的高度要低,就dfs。

http://paste.ubuntu.com/6953207/

 

http://poj.org/problem?id=1014

多重揹包的應用,很少說。

http://paste.ubuntu.com/6954121/

 

http://poj.org/problem?id=1160

dp[i][j]表示前i個郵局設立在前j個村莊的最短距離和,sum[i][j]表示第i個村莊到第j個村莊創建一個郵局的距離和,顯然,該郵局創建在i,j的中點位置最佳,因而咱們能夠得出:dp[i][j] = min(dp[i][j], dp[i-1][k] + sum[k + 1][j]) ( 1 <=k < j).而sum[i][j] = sum[i][j-1] + pos[j] - pos[(i + j) /2], 最後注意一下初始化就能夠了。

http://paste.ubuntu.com/6957889/

 

http://poj.org/problem?id=1179

pair<long long, long long > dp[i][j]表示第i個數字到第j個數字通過運算後的最小值以及最大值,而後就須要枚舉斷開的位置了,而且因爲是環,須要取模處理,最後就是記憶化搜索了,須要注意的就是兩個最小值相乘也有可能成爲最大值。

http://paste.ubuntu.com/6960005/

 

http://poj.org/problem?id=1141

記憶化搜索,dp[i][j]表示從第i個數字到第j個數字最少要插入的字符數,因而能夠得出dp[i][j] = dp[i][k] + dp[k + 1][j](i <=k < j),而且當str[i] ==‘(’ && str[j] == ')' ||  str[i] == '[' && str[j] == ']'時,有dp[i][j] = dp[i + 1][j - 1];因爲涉及到打印路徑,須要開闢一個數組來記錄每次選擇的結果,而後遞歸求解。

http://paste.ubuntu.com/6964829/

 

http://poj.org/problem?id=1170

這道題要用到六進制壓縮,若是第一種物品表示爲state = 1,那麼第二種物品表示爲state = 6,而且以此類推,總狀態就可表示爲S = num1 * 1 + num2 * 6 + ...,而後就是用到徹底揹包了, 設dp[state]表示狀態爲state時的最小的價格。

http://paste.ubuntu.com/6969768/

 

http://poj.org/problem?id=1191

劉汝佳黑書上的題目,p116.

記憶化搜索,dp[x1][y1][x2][y2][k]表示左上角(x1,y1) -> (x2, y2)的區域切割k塊的最小值。

1 double ans = 1LL << 60;
2 for (int i = x1; i < x2; i++) {
3     ans = min(ans, dfs(x1, y1, i, y2, k - 1) + getSum(i + 1, y1, x2, y2));
4     ans = min(ans, dfs(i + 1, y1, x2, y2, k - 1) + getSum(x1, y1, i, y2));
5 }
6 for (int i = y1; i < y2; i++) {
7     ans = min(ans, dfs(x1, y1, x2, i, k - 1) + getSum(x1, i + 1, x2, y2));
8     ans = min(ans, dfs(x1, i + 1, x2, y2, k - 1) + getSum(x1, y1, x2, i));
9 }

http://paste.ubuntu.com/6970765/

 

http://poj.org/problem?id=1661

調一個BUG調了一個從下午一直調到如今,最後發現原來是有一處地方發生了溢出!這種低級錯誤之後必定要杜絕!仍是說說題目吧:

dp[i][0]表示從第i層的左端跳下所用的最短期,dp[i][1]表示從第i層的右端跳下所用的最短期,因而咱們經過能夠判斷端點的位置的關係得出遞推方程。

http://paste.ubuntu.com/6975857/

 

http://poj.org/problem?id=1745

dp[i][j]表示對前i個數字進行操做計算後MOD % k後爲j, 那麼若是dp[i][j]爲true,則dp[i + 1][(j + num[i + 1]) % K] 和 dp[i + 1][ ( j - num[i + 1]) % K]均爲true.

http://paste.ubuntu.com/6976041/

 

http://poj.org/problem?id=1837

和上一題差很少,都須要加一個偏移量,這裏我選擇偏移量爲7500(假設全部砝碼都掛在最右,則最大力距爲20*15*25),dp[i][j]表示掛了前i個砝碼,力距爲j的方案數,因而咱們能夠得出:dp[i][j + pos[k] * g[i]] += dp[i - 1][j] ( 1 <= k <= C)。最後就是初始化的問題了,假設第一個砝碼每一個位置都掛一遍,因而有dp[1][pos[i] * g[1] + 7500] = 1( 1 <= i <= C).

http://paste.ubuntu.com/6979698/

 

http://poj.org/problem?id=1836

一道不錯的題目,咱們能夠從左向右求一次最長上升子序列,從右向左求一次最長上升子序列,分別用Up數組和Down數組老保存,而後用dp1[i]表示1-i的最長上升序列長度,dp2[i]表示i-n的最長降低上升序列,而且用mark1[]和mark2[]數組來記錄這個最長上升序列是否必需要包含i點,因而剩下的問題就直接枚舉中間點就能夠了。

http://paste.ubuntu.com/6980546/

 

http://poj.org/problem?id=1952

一道很不錯的dp題,題目的意思是要求最長降低子序列的個數,這個很容易,可是有一個要求,就是若是兩個最長降低子序列是同樣的,就只能算一個,這個須要處理一下。

http://paste.ubuntu.com/6993356/

 

http://poj.org/problem?id=2137

dp[i][j][k]表示從第一頭牛的j位置到第i頭牛的k位置的最短距離,因而能夠得出dp[i][j][k] = min(dp[i][j][k], dp[i-1][j][l] + getDist(k, l)),因爲要圍成圈,最後首位相連便可,須要注意初始化問題。

http://paste.ubuntu.com/6993710/

 

http://poj.org/problem?id=2184

dp[i][s]表示前i頭奶牛聰明度爲s是的最大的快樂度,這就相似與01揹包的處理方法了,可是因爲體積能夠爲負,這時咱們須要加一個偏移量,而且處理的時候從小到大進行處理.

http://paste.ubuntu.com/6997548/

 

http://poj.org/problem?id=2241

一塊磚一共有6中擺放方式,dp[i]表示使用前i塊磚所能達到的最大的高度,因而有dp[i] = max(dp[i], dp[j] + node[i].z) (0 <= j < i) 賦初值的時候要注意,當只放一塊磚的時候,是每種狀況均可以的(一開始沒注意到,wa了好屢次)。

http://paste.ubuntu.com/6999070/

 

http://poj.org/problem?id=2264

本題的關鍵之處就是求出最長公共子序列而且用另一個數組來標記,而後就是遞歸輸出最後的ans。

http://paste.ubuntu.com/6999927/

 

http://poj.org/problem?id=2353

dp[i][j]表示到第i層第j個房間的最小值,因而有dp[i][j] = min(dp[i- 1][j], dp[i][j - 1], dp[i][j + 1]) + num[i][j].而後分別從左向右dp和從右向左dp,同時記錄路徑就能夠了,最後遍歷最後一行找值最小的列,遞歸輸出便可。

http://paste.ubuntu.com/7009043/

 

http://poj.org/problem?id=3612

dp[i][j]表示第i個高度爲j時前i個的最小值,很容易想到這樣一個遞推關係式:dp[i][j] = min(dp[i-1][k] + abs(k-j) * C + (num[i] - j) * (num[i] - j));可毫無疑問,複雜度過高。。。只能想辦法優化一下:

對於k >= j有:dp[i][j]=j*c+(a[i]-j)*(a[i]-j)+min(dp[i-1][k]-k*c) (1<=k<=j)

對於k < j 有:dp[i][j]=-j*c+(a[i]-j)*(a[i]-k)+min(dp[i-1][k]+k*c) (j<k<=m)

low[j]表示min(dp[i-1][k]-k*c)(1<=k<=j) high[j]=min(dp[i-1][k]+k*c)(j<k<=m)

因而能夠預處理出這兩個數組,在轉移的時候就可以作到O(1)了,這樣也就下降複雜度了。

http://paste.ubuntu.com/7009907/

 

http://poj.org/problem?id=2385

dp[i][0][j]表示到第i秒在1號樹下返回j次的最大值,dp[i][1][j]表示到第i秒在2號樹下返回j次的最大值。而後求一下遞推關係便可。

http://paste.ubuntu.com/7010136/

 

http://poj.org/problem?id=2392

先按ai的值從小到大排,而後就是多重揹包了。

http://paste.ubuntu.com/7010489/

 

http://poj.org/problem?id=2479

求兩個不相交的連續子段的最大和,能夠從左到右掃一遍,從右到左掃一遍而且分別用dp1[],dp2[]來記錄,而後更新最大值便可。

http://paste.ubuntu.com/7014856/

 

http://poj.org/problem?id=2486

一道很不錯的題目,dp[i][j][0]表示從節點i出發,能走j步,最後回到i點的最大值,dp[i][j][1]表示從i點出發走j步最後停留在i的某棵子樹上點最大值,因而能夠得出一下三種狀況:

dp[0][s][j+2]=Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);//從s出發,要回到s,須要多走兩步s- >t,t- > s,分配給t子樹k步,其餘子樹j-k步,都返回
dp[1][s][j+2]=Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);//不回到s(去s的其餘子樹),在t子樹返回,一樣有多出兩步
dp[1][s][j+1]=Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);//先遍歷s的其餘子樹,回到s,s - > t, 遍歷t子樹,在當前子樹t不返回,多走一步.

http://paste.ubuntu.com/7015701/

 

http://poj.org/problem?id=2559

l[i]表示大於等於h[i]的最左邊的位置,r[i]表示大於等於h[i]的最右邊的位置,這樣能夠預處理出l[],r[],而後ans = max(ans, r[i] - l[i] + 1) * h[i])( 1 <= i  <= n).

http://paste.ubuntu.com/7016077/

 

http://poj.org/problem?id=2663

先把3行n列轉成n行3列,dp[row][state]表示第i行狀態爲state的總數,因而dp[row][s2] += dp[row - 1][s1] 其中s1,s2兩狀態合法,這題與poj2411幾乎同樣。

http://paste.ubuntu.com/7016354/

 

http://poj.org/problem?id=2817

狀態壓縮,dp[state][i]表示當前狀態爲state,而且以第i個字符串開頭的最大匹配數,這裏的狀態須要解釋一下,指的是用到了那幾個字符串。因而咱們能夠獲得遞推關係:

dp[state | (1 << j] = min(dp[state | (1 << j)], dp[state][i] + num[i][j]),其中num[i][j]指的是字符串i和字符串j的最大匹配數。

http://paste.ubuntu.com/7026396/

 

http://poj.org/problem?id=2923

狀態壓縮,首先預處理出哪些物品可以被兩輛車一塊兒帶走,dp[state]表示當前爲狀態爲state下所須要的最小的次數。而後就是赤裸裸的狀壓dp了。

http://paste.ubuntu.com/7026803/

 

http://poj.org/problem?id=3036

首先把六邊型映射到直角座標,對於點(x,y),可以走的6個點分別爲:(x, y - 1), (x, y + 1), (x - 1, y), (x + 1, y), (x + 1, y - 1), (x - 1, y + 1)。

dp[step][x][y]表示當前在點(x,y),已經走了step步的方法數,因爲走的時候座標可能爲負,因而總體平移,令(15,15)爲座標原點,dp[0][15][15] =1,那麼最後要求的不就是dp[n][15][15]了。

http://paste.ubuntu.com/7030831/

 

http://poj.org/problem?id=3042

區間dp,dp[i][j][0]表示i到j之間已經走過,而且如今在i點的最小值,dp[i][j][1]表示如今在j點,因而對於在i點,可能從i +1 - > i, 也可能從j - i,即:

dp[i][j][0] = min(dp[i + 1][j][0]  + (n - (j - i) ) * (pos[i + 1] - pos[i]), dp[i + 1][j][1] + (n - (j - i)) * (pos[j] - pos[i]));

同理對於當前在j點,也能夠獲得向相應的方程:dp[i][j][1] = min(dp[i][j-1][1] + (n - (j - i)) * (pos[j] - pos[j - 1), dp[i][j - 1][0] + (n - (j - i)) * (pos[j] - pos[i])).

而後須要注意的就是初始話的問題了,找到L在原序列中的位置。

http://paste.ubuntu.com/7031972/

 

http://poj.org/problem?id=3046

dp[i][j]表示用前i中類型組成序列長度爲j的方法數,因而就有dp[i][j] += dp[i - 1][j - k] (0 <= k <= num[i]).

能夠優化的地方,採用滾動數組,不過每次都必須清空,一開始沒這麼幹,樣例都過不了。

http://paste.ubuntu.com/7032709/

 

http://poj.org/problem?id=3132

dp[i][j]表示用j個素數獲得和爲n的方案數,這就相似與01揹包了。

狀態轉移方程:dp[i][j] += dp[i - x][j - 1](其中x爲素數);

http://paste.ubuntu.com/

 

http://poj.org/problem?id=3140

dp[u]表示以u爲根的全部子樹的和,則有ans = min(ans, (sum - dp[u]) - dp[u]).在dfs的過程當中不斷更新便可。

http://paste.ubuntu.com/7036461/

 

http://poj.org/problem?id=1185

dp[i][j][k]表示第i行狀態爲j,第i - 1行狀態爲k的最大可放置數量.

首先預處理出可行的狀態,即相鄰的兩個1之間的距離至少要大於2。

而後就是狀壓dp搞搞了.dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + num[i])(j, k, l狀態不衝突,num[i]爲第i行此時可以放的個數).

http://paste.ubuntu.com/7059384/

 

http://poj.org/problem?id=2288

dp[i][j][s]表示當前點爲j,上一點是i,當前狀態爲s下的最小值;

ways[i][j][s]表示當前點爲j,上一點爲i,當前狀態爲s下的相同最小值的個數.

注意一下初始化。

http://paste.ubuntu.com/7060817/

相關文章
相關標籤/搜索