生活随笔
收集整理的這篇文章主要介紹了
[JZOJ5426]摘Galo
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題目大意:
有一棵n個結(jié)點的樹,每個點都有一個權(quán)值,你要從中選出不超過k+1個點使得權(quán)值和盡量大。
同時要注意如果一個點被選擇,那么它的子樹和這個點到根結(jié)點路徑上的點不能被選擇。
思路:
很水的樹形DP。
f[i][j]表示以i為根的子樹中選擇了j個點的最大權(quán)值和。
狀態(tài)轉(zhuǎn)移方程f[par[i]][k]=max{f[par[i]][k]+f[i][j]};
轉(zhuǎn)移的時候可能會被覆蓋掉,因此用一個臨時數(shù)組g來保存。
for的時候不能for滿,不然就變成O(nk^2)的了,只有60分。
數(shù)組可能會開不下,要用vector。
1 #include<cstdio>
2 #include<cctype>
3 #include<vector>
4 typedef
long long int64;
5 inline
int getint() {
6 register
char ch;
7 while(!isdigit(ch=
getchar()));
8 register
int x=ch^
'0';
9 while(isdigit(ch=getchar())) x=(((x<<
2)+x)<<
1)+(ch^
'0');
10 return x;
11 }
12 const int N=
100001;
13 int par[N],w[N],size[N];
14 std::vector<std::vector<int64> >
f;
15 std::vector<int64>
g;
16 int main() {
17 const int n=getint(),k=getint()+
1;
18 for(register
int i=
2;i<=n;i++
) {
19 par[i]=getint(),w[i]=
getint();
20 }
21 f.resize(n+
1);
22 g.resize(k+
1);
23 for(register
int i=
1;i<=n;i++) size[i]=
1;
24 for(register
int i=n;i>
1;i--
) {
25 size[par[i]]+=
size[i];
26 if(f[i].empty()) f[i].resize(k+
1);
27 if(f[par[i]].empty()) f[par[i]].resize(k+
1);
28 g=
f[par[i]];
29 f[i][
1]=std::max(f[i][
1],(int64)w[i]);
30 for(register
int j=
1;j<=std::min(size[i],k);j++
) {
31 for(register
int l=
0;l<=std::min(size[par[i]],k)-j;l++
) {
32 g[l+j]=std::max(g[l+j],f[par[i]][l]+
f[i][j]);
33 }
34 }
35 f[par[i]]=
g;
36 f[i].clear();
37 }
38 int64 ans=
0;
39 for(register
int i=
0;i<=k;i++) ans=std::max(ans,f[
1][i]);
40 printf(
"%lld\n",ans);
41 return 0;
42 }
?
轉(zhuǎn)載于:https://www.cnblogs.com/skylee03/p/7788504.html
總結(jié)
以上是生活随笔為你收集整理的[JZOJ5426]摘Galo的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。