P1040 加分二叉樹 區間dp

2022-05-01 17:09:08 字數 3178 閱讀 4762

設乙個nn個節點的二叉樹tree的中序遍歷為(1,2,3,…,n1,2,3,…,n),其中數字1,2,3,…,n1,2,3,…,n為節點編號。每個節點都有乙個分數(均為正整數),記第ii個節點的分數為di,treedi,tree及它的每個子樹都有乙個加分,任一棵子樹subtreesubtree(也包含treetree本身)的加分計算方法如下:

subtreesubtree的左子樹的加分× subtreesubtree的右子樹的加分+subtreesubtree的根的分數。

若某個子樹為空,規定其加分為11,葉子的加分就是葉節點本身的分數。不考慮它的空子樹。

試求一棵符合中序遍歷為(1,2,3,…,n1,2,3,…,n)且加分最高的二叉樹treetree。要求輸出;

(1)treetree的最高加分

(2)treetree的前序遍歷

輸入格式:

第11行:11個整數n(n<30)n(n<30),為節點個數。

第22行:nn個用空格隔開的整數,為每個節點的分數(分數<100<100)。

輸出格式:

第11行:11個整數,為最高加分(ans \le 4,000,000,000≤4,000,000,000)。

第22行:nn個用空格隔開的整數,為該樹的前序遍歷。

輸入樣例#1: 複製

5

5 7 1 2 10

輸出樣例#1: 複製

145

3 1 2 4 5

難以下手 看到是dfs專題一直想著用dfs來解

這題用區間dp很方便能解

f(i,j)=*f+頂點i的分數 (i

#includeusing

namespace

std;

//input by bxd

#define rep(i,a,b) for(int i=(a);i<=(b);i++)

#define repp(i,a,b) for(int i=(a);i>=(b);i--)

#define ri(n) scanf("%d",&(n))

#define rii(n,m) scanf("%d%d",&n,&m)

#define riii(n,m,k) scanf("%d%d%d",&n,&m,&k)

#define rs(s) scanf("%s",s);

#define ll long long

#define pb push_back

#define fi first

#define rep(i,n) for(int i=0;i

#define clr(a,v) memset(a,v,sizeof a)

/////////////////////////////////

//#define inf 0x3f3f3f3f

#define n 100

introot[n][n];

ll dp[n][n];

intn;

intfirst;

ll search1(

int l,int r)//

區間記憶化dp}}

return

dp[l][r];

}void print(int l,int

r)int

main()

cout

<1,n)<

first=1

; print(

1,n);

}

view code

非記憶化

#includeusing

namespace

std;

//input by bxd

#define rep(i,a,b) for(int i=(a);i<=(b);i++)

#define repp(i,a,b) for(int i=(a);i>=(b);i--)

#define ri(n) scanf("%d",&(n))

#define rii(n,m) scanf("%d%d",&n,&m)

#define riii(n,m,k) scanf("%d%d%d",&n,&m,&k)

#define rs(s) scanf("%s",s);

#define ll long long

#define pb push_back

#define fi first

#define rep(i,n) for(int i=0;i

#define clr(a,v) memset(a,v,sizeof a)

/////////////////////////////////

//#define inf 0x3f3f3f3f

#define n 100

introot[n][n];

ll dp[n][n];

intn;

intfirst;

void print(int l,int

r)int

main()

rep(len,

1,n)

rep(i,

1,n)

}cout

<1][n]<

first=1

; print(

1,n);

}

view code

更加簡潔

#include#include

using

namespace

std;

int n,v[39],f[47][47],i,j,k,root[49][49

];void print(int l,int

r) printf(

"%d

",root[l][r]);

print(l,root[l][r]-1

); print(root[l][r]+1

,r);

}int

main()

for(i=n; i>=1; i--)

for(j=i+1; j<=n; j++)

for(k=i; k<=j; k++)

}printf(

"%d\n

",f[1

][n]);

print(

1,n);

return0;

}

view code

P1040 加分二叉樹

設乙個n個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 subtree...

P1040 加分二叉樹

設乙個nn個節點的二叉樹tree的中序遍歷為 1,2,3,n1,2,3,n 其中數字1,2,3,n1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第ii個節點的分數為di,treedi,tree及它的每個子樹都有乙個加分,任一棵子樹subtreesubtree 也包含treetree本...

P1040 加分二叉樹

題目 很明顯的一道區間dp題目。和acwing上的金字塔有點像。表面上感覺是樹形dp,實則不然。題中給出的1 n是中序遍歷,按照區間dp的套路 設f l r 為中序遍歷是l r的子樹的最大加分值。那麼劃分點佷顯然就是列舉一顆子樹的根節點,再加上這棵樹是一顆二叉樹就更好辦了。dp方程如下 for in...