poj 1155 TELE

题目描述:...

解法:

    树形dp+分组背包。

    dp[i][j]记录以i为根的子树分配j个用户时的最大收益,cnt[i]记录以i为根的子树有几个叶子节点,对于每个i,背包容量即为cnt[i]的大小。

    将i的每个子节点看作一组,这组背包的物品重量即为1~cnt[son[i]],由于只能从每组中选出一种物品,所以可以看做分组背包。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #define N 3010
 6 using namespace std;
 7 const int inf=(1<<30);
 8 struct Edge{
 9     int next,len;
10 };
11 vector<Edge>V[N];
12 int dp[N][N];
13 int cnt[N];
14 void init(){
15     for(int i=1;i<N;i++)V[i].clear();
16     for(int i=0;i<N;i++)
17         for(int j=0;j<N;j++)
18             dp[i][j]=-inf;
19     for(int i=0;i<N;i++)
20         dp[i][0]=0;
21     memset(cnt,0,sizeof(cnt));
22 }
23 int dfs(int n){
24     if(cnt[n]!=0)return  cnt[n];
25     cnt[n]=0;
26     for(int i=0;i<V[n].size();i++){
27         dfs(V[n][i].next);
28         cnt[n]+=cnt[V[n][i].next];
29     }
30     return cnt[n];
31 }
32 void DP(int n){
33     if(V[n].size()==0)
34         return ;
35     for(int i=0;i<V[n].size();i++){
36         DP(V[n][i].next);
37         for(int k=cnt[n];k>=1;k--)
38             for(int j=1;j<=cnt[V[n][i].next];j++)
39             if(k>=j)
40                 dp[n][k]=max(dp[n][k],dp[n][k-j]+dp[V[n][i].next][j]+V[n][i].len);
41 
42     }
43 }
44 int main(){
45     int n,m;
46     while(cin>>n>>m){
47         init();
48         for(int i=1;i<=n-m;i++){
49             int k,a,c;
50             cin>>k;
51             while(k--){
52                 cin>>a>>c;
53                 Edge E;
54                 E.next=a;E.len=-c;
55                 V[i].push_back(E);
56             }
57         }
58         for(int i=n-m+1,j=1;i<=n;i++,j++){
59             int c;
60             cin>>c;
61             dp[i][1]=c;
62             cnt[i]=1;
63         }
64         dfs(1);
65         DP(1);
66         for(int i=cnt[1];i>=1;i--)
67             if(dp[1][i]>=0){
68                 cout<<i<<endl;
69                 break;
70             }
71     }
72     return 0;
73 }
posted @ 2012-10-29 21:31  silver__bullet  阅读(166)  评论(0编辑  收藏  举报