有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有只有1個兒子的結點)
這棵樹共有n個結點(葉子點或者樹枝分叉點),編號為1-n,樹根編號一定是1。
我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹
2 5
3 4
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。
給定需要保留的樹枝數量,求出最多能留住多少蘋果。
輸入格式:
第1行2個數,n和q(1<=q<= n,1n表示樹的結點數,q表示要保留的樹枝數量。接下來n-1行描述樹枝的資訊。
每行3個整數,前兩個是它連線的結點的編號。第3個數是這根樹枝上蘋果的數量。
每根樹枝上的蘋果不超過30000個。
輸出格式:
乙個數,最多能留住的蘋果的數量。
輸入樣例#1:
5 2輸出樣例#1:1 3 1
1 4 10
2 3 20
3 5 20
21
樹上的揹包問題,很容易就想到如果刪除乙個子節點,那麼以這個節點的棵子樹就會全部刪除,那麼對這個子樹刪除的節點就不能超過子節點個數。所以我們先dfs一邊,求出有多少乙個節點有多少子節點,並標記處father,保證不會到father
f[i][j]《在i這個子樹中刪除j個邊的最大值,然後貪心維護最大就好了
#include#includeby:s_a_b_e_r#include
#include
#include
#define ll long long
using
namespace
std;
const
int maxn=150
;int
read()
while('0'
<=ch&&ch<='9')
return f*an;
}int
f[maxn],dp[maxn][maxn],cnt,fa[maxn],son[maxn],q,n;
bool
vis[maxn],vis2[maxn];
struct
saberb[maxn
<<1
];void add(int x,int y,int
z)void dfs(int
x) }
}void dp(int
x) }
}int
main()
dfs(1);
dp(1);
cout
<1
][q];
return0;
}
樓上一直堅持兩遍dfs,其實一遍就好了啊qwq
而且既然只向下dp,存單向邊就可以啦(但是要存一下father)
因為是二叉樹所以非常好辦
如果點x的子樹一共要保留i根樹枝
肯定是一部分(j)分給左子樹,剩下的(i-j)給右子樹
於是就可以愉快地填表dp了^_^
#include#includeby:wypxusing
namespace
std;
const
int n=109
;int
n,q,p[n],fa[n],f[n][n],cnt,son[n];
struct
edgee[n
<<1
];void add(int u,int v,int
w)void dfs(intu)}
intmain()
else
}dfs(1);
cout
<1][q]<
return0;
}
Luogu P2015 二叉蘋果樹
題目描述 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。給定...
Luogu P2015 二叉蘋果樹
題目鏈結 樹上零一dp 記憶化搜尋 如果是空結點 如果是葉子結點直接返回蘋果數 以上都不滿足的話,dp狀態轉移 設定dp的轉移,轉移到左右兒子結點 for int i 1 i結果31分 1.說白了,記憶化搜尋還不是掌握的特別好 2.其次狀態設計不是特別好,在儲存左右兒子時,應該該需要儲存邊的 inc...
Luogu P2015二叉蘋果樹(DP,DFS)
題目鏈結 設f i j k 表示給以i為根節點的子樹分配j條可保留的樹枝名額的時候,狀態為k時能保留的最多蘋果。k有三種情況。k 1 我只考慮子樹的左叉,不考慮子樹的右叉,此時子樹能保留的最多的蘋果。k 2 我只考慮子樹的右叉,不考慮子樹的左叉,此時子樹能保留的最多的蘋果。k 3 我既考慮子樹的左叉...