DP专练1( [NOIP 2003]加分二叉树 + 太空梯 )
我們先慢慢來
- 加分二叉樹
- 題目
- 題解
- 簡單講解前序//中序//后序遍歷
- 代碼實現
- 太空梯
- 題目
- 題解
- 代碼實現
加分二叉樹
題目
題解
簡單講解前序//中序//后序遍歷
其實說白了,這個*序就是根root的遍歷順序
先序就是root–>left–>right
中序就是left–>root–>right
后序就是left–>right–>root
上圖:
那么這個圖很完美啊!!有兩個兒子的,又有只有左兒子的,還有只有右兒子的
先序:1 2 4 3 5
中序:4 2 1 3 5
后序:4 2 5 3 1
以講解先序遍歷順序為例:
首先找到根root=1,然后再去搜索左兒子2,這個時候2為新子樹的根,
接著搜索2的左兒子4,4是葉子節點回溯,其次搜索2的右兒子,無,回溯
回到最上面搜索1的右兒子3,然后搜索3的左兒子,空,回溯,
最后找到右兒子5,葉子節點,回溯
講解一個順序把近幾年所學的邏輯順序詞給憋完了
那么這道題其實就很水,加上數據那么小,直接暴力跑生成樹就ok了
對于搜索的這個新子樹的范圍l,r,枚舉這之間任何一個i為根的情況,
求個MAX
記錄個root=i,最后用遞歸輸出即可
代碼實現
#include <cstdio> #define MAXN 35 int dp[MAXN][MAXN]; int root[MAXN][MAXN]; int a[MAXN]; int n; void build ( int l, int r ) {if ( dp[l][r] ) return;if ( l > r ) {dp[l][r] = 1;return;}if ( l == r ) {dp[l][r] = a[l];root[l][r] = l;return;}for ( int i = l;i <= r;i ++ ) {build ( l, i - 1 );build ( i + 1, r );if ( dp[l][i - 1] * dp[i + 1][r] + a[i] > dp[l][r] ) {dp[l][r] = dp[l][i - 1] * dp[i + 1][r] + a[i];root[l][r] = i;}} } void print ( int l, int r ) {if ( ! root[l][r] ) return;printf ( "%d ", root[l][r] );print ( l, root[l][r] - 1 );print ( root[l][r] + 1, r ); } int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ ) scanf ( "%d", &a[i] );build ( 1, n );printf ( "%d\n", dp[1][n] );print ( 1, n );return 0; }太空梯
題目
題目描述
有一群牛要上太空。他們計劃建一個太空梯-----用一些石頭壘。他們有k(1<=k<=400)種不同類型的石頭,每一種石頭的高度為h_i(1<=h_i<=100),數量為c_i(1<=c_i<=10),并且由于會受到太空輻射,每一種石頭不能超過這種石頭的最大建造高度a_i(1<=a_i<=40000)。幫助這群牛建造一個最高的太空梯。
輸入格式
第一行為一個整數即k。第2行到第k+1行每一行有3個數,代表每種類型魔法石的特征,即高度h,限制高度a和數量c。
輸出格式
一個整數,即修建太空梯的最大高度。
樣例
樣例輸入
3
7 40 3
5 23 8
2 52 6
樣例輸出
48
【樣例說明】 15+21+12
最底下為3塊石頭2型,中間為3塊石頭1型,上面為6塊石頭3型。放置4塊石頭2型和3塊石頭1型是不可以的,因為頂端的石頭1型的高度超過了40的限制。
題解
這道題也是一個多重背包水題
首先肯定會想到排序,因為石頭類型的高度限制越小,肯定越往下排,往上很容易超過最高限制
然后我們就定義一個:bool類型的dp[i][j]
表示只使用1~i種類型石頭且總高度為j的剋行性,
可以湊出來并且合法就是1,反之0
dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*stone[i].h]) k表示i石頭使用的個數
我們知道dp[i][j]只與i-1上一種石頭類型有關
所以我們就簡化成一維
dp[j]=max(dp[j], dp[j-k*stone[i].h])
這里還是像其他dp題一樣,j要從大到小枚舉
簡單解釋為什么;
當我們i++后要重新開始枚舉j,如果是從小到大,
因為我們是一維,就會對上一次i改變后的答案進行更改
而我們到后面的會有 j - k * stone[i].h 的操作,這個時候我們其實是需要i-1的狀態,
如果從小到大狀態答案就被覆蓋了,最后ans也會出錯
代碼實現
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define MAXN 405 #define MAX 40005 struct node {int h, limit, c; }stone[MAXN]; bool cmp ( node x, node y ) {return x.limit < y.limit; } int n, Max; bool dp[MAX]; int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ ) {scanf ( "%d %d %d", &stone[i].h, &stone[i].limit, &stone[i].c );Max = max ( Max, stone[i].limit );}sort ( stone + 1, stone + n + 1, cmp );dp[0] = 1;for ( int i = 1;i <= n;i ++ )for ( int j = Max;j >= 0;j -- )for ( int k = 0;k <= stone[i].c;k ++ ) {if ( j < k * stone[i].h || j > stone[i].limit ) break;else dp[j] = max ( dp[j], dp[j - k * stone[i].h] );}for ( int i = Max;i >= 0;i -- )if ( dp[i] ) {printf ( "%d\n", i );break;}return 0; }好了,就到這里吧,這只是練練手,不然怎么叫專練1呢~~
等會兒我就會攜帶著一堆毒瘤來見大家的,bye~
總結
以上是生活随笔為你收集整理的DP专练1( [NOIP 2003]加分二叉树 + 太空梯 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 历史上的今天(history)+ 勇者斗
- 下一篇: 如何进行路由器安全设置如何设置路由器的安