標籤:get using 獲得 ffffff cstring read define poj 傳送門
題目傳送門 題解:
第一道樹上背包題qaq
考慮每個節點在最終答案中的類型:1,不經過;2,經過但不返回;3,經過且返回 (返回的定義是最終的停止節點不位於該節點的子樹中)
對於第一種類型的節點,不用考慮。
對於後兩種類型,我們設f[i][j][0]表示在第i個節點的子樹中走j步且最終回到i節點所能夠獲得的最大權值,f[i][j][1]表示最終不回到i節點獲得的最大權值。
對於一個節點的每一個子節點,都要選擇其中的一種狀態。我們可以把該問題抽象成分組背包問題:一個容量為j的背包,有siz組物品(siz相當於子節點數目),每組物品只能選一種。那麼我們可以得到狀態轉移方程:
f[i][j][0] = max{f[v][k][0]+f[i][j-k-2][0]} (既然要回到該節點,那麼對於子節點v來說肯定也要回到v節點,且下去上來各一步,故多用掉兩步)
f[i][j][1] = max{f[v][k][0]+f[i][j-k-2][1]} (對於v節點來說,下去不回來,那麼其他的節點下去後就必須回來)
f[i][j][1] = max{f[v][k][1]+f[i][j-k-1][0]} (該節點回來,那麼其他節點可以不回來)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define LL long long 5 #define RI register int 6 using namespace std; 7 const int INF = 0x7ffffff ; 8 const int N = 100 + 10 ; 9 const int K = 200 + 10 ;10 11 inline int read() {12 int k = 0 , f = 1 ; char c = getchar() ;13 for( ; !isdigit(c) ; c = getchar())14 if(c == ‘-‘) f = -1 ;15 for( ; isdigit(c) ; c = getchar())16 k = k*10 + c-‘0‘ ;17 return k*f ;18 }19 20 struct Edge {21 int to, next ;22 }e[N<<1] ;23 int n, k, cnt = 0 ; int head[N], w[N], f[N][K][2] ; // 0表示回來,1表示不回來 24 inline void add_edge(int x,int y) {25 e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt ;26 }27 28 void dfs(int x,int fa) {29 for(int j=0;j<=k;j++) f[x][j][0] = f[x][j][1] = w[x] ;30 for(int i=head[x];i;i=e[i].next) {31 int y = e[i].to ; if(y == fa) continue ;32 dfs(y,x) ;33 for(int j=k;j>=0;j--) {34 for(int kk=0;kk<=j;kk++) {35 if(j >= kk+2) f[x][j][0] = max(f[x][j][0],f[x][j-kk-2][0]+f[y][kk][0]) ;36 if(j >= kk+2) f[x][j][1] = max(f[x][j][1],f[x][j-kk-2][1]+f[y][kk][0]) ;37 if(j >= kk+1) f[x][j][1] = max(f[x][j][1],f[x][j-kk-1][0]+f[y][kk][1]) ;38 }39 }40 }41 }42 43 int main() {44 while(~scanf("%d %d",&n,&k)) {45 cnt = 0 ; memset(head,0,sizeof(head)) ;46 for(int i=1;i<=n;i++) w[i] = read() ;47 for(int i=1;i<n;i++) {48 int x = read(), y = read() ;49 add_edge(x,y) ; add_edge(y,x) ;50 }51 dfs(1,0) ;52 printf("%d\n",max(f[1][k][0],f[1][k][1])) ;53 }54 return 0 ;55 }
第一次就錯在了子節點中只能有一個下去不回來qwq
Apple Tree (POJ2486