【問題描述】
設乙個n個節點的二叉樹tree的中序遍歷為(l,2,3,…,n),其中數字1,2,3,…,n為節點編號。每個節點都有乙個分數(均為正整數),記第j個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree(也包含tree本身)的加分計算方法如下:
subtree的左子樹的加分×subtree的右子樹的加分+subtree的根的分數
若某個子樹為主,規定其加分為1,葉子的加分就是葉節點本身的分數。不考慮它的空
子樹。試求一棵符合中序遍歷為(1,2,3,…,n)且加分最高的二叉樹tree。要求輸出;
(1)tree的最高加分
(2)tree的前序遍歷
【輸入格式】
第1行:乙個整數n(n<30),為節點個數。
第2行:n個用空格隔開的整數,為每個節點的分數(分數<100)。
【輸出格式】
第1行:乙個整數,為最高加分(結果不會超過4,000,000,000)。
第2行:n個用空格隔開的整數,為該樹的前序遍歷。
解題思路:這題我覺得歸為區間dp比較合適。。由於給出的是中序遍歷,所以設遍歷中的第i個為根,則有第1到i-1為左子樹的中序遍歷,第i+1到n為右子樹的中序遍歷,這樣就找到了最優子結構的性質,對於每乙個中序遍歷我們只需要列舉它的根即可。設f[i][j]為i到j作為中序遍歷時的最大得分,則可以得到狀態轉移方程f[i][j]=max(f[i][k-1]*f[k+1][j])+point[k],i<=k<=j。
**(很久以前寫的,略醜):
programpointtree(input,output);
var f:array[0..35,0..35]of longint;
a:array[0..35]of longint;
n,i,j,k,max:longint;
procedure findmax(s,e:longint);
var i,k,max:longint;
begin
max:=0;k:=-1;
for i:=s to e do
if f[s,i-1]*f[i+1,e]+a[i]>max then beginmax:=f[s,i-1]*f[i+1,e]+a[i];k:=i;end;
if k<>-1 then
begin
write(k,' ');
findmax(s,k-1);
findmax(k+1,e);
end;
end;
begin
assign(input,'pointtree.in');
reset(input);
readln(n);
filldword(f,sizeof(f)div 4,1);
for i:=1 to n do
begin
read(a[i]);
f[i,i]:=a[i];
f[i-1,i]:=a[i-1]+a[i];
end;
for i:=3 to n-1 do
for j:=1 to n do
for k:=j to j+i-1 do
iff[j,k-1]*f[k+1,j+i-1]+a[k]>f[j,j+i-1] thenf[j,j+i-1]:=f[j,k-1]*f[k+1,j+i-1]+a[k];
max:=0;
for i:=1 to n do
if f[1,i-1]*f[i+1,n]+a[i]>max thenmax:=f[1,i-1]*f[i+1,n]+a[i];
writeln(max);
findmax(1,n);
close(input);
end.
NOIP 2003 加分二叉樹
問題描述 設乙個n個節點的二叉樹tree的中序遍歷為 l,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第j個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 su...
NOIP 2003 加分二叉樹
評測傳送 這個題可以記憶化搜尋做的。注意邊界條件。對於先序遍歷,遞迴就可以了 在dfs的時候用乙個陣列記錄根節點就可以了 include include include include include include define ll long long using namespace std i...
動態規劃 NOIP2003 加分二叉樹
題目 感覺這個題挺難的啊 畢竟dp很弱 乙個比較經典的樹形dp 我們用f i j 表示區間i j的最大加分 dp i j 表示區間i j的最大加分時的根節點是什麼 所以初始化f i i a i dp i i i 然後就是迴圈列舉區間 然後在每個區間中在列舉根節點 如果發現當前區間的左子樹的加分 右子...