poj 1155 TELE

本文介绍了一种结合树形动态规划与分组背包问题的算法解决方案。该方案通过定义dp[i][j]来记录以节点i为根的子树分配j个用户时的最大收益,并利用分组背包的思想解决子节点间的物品选择问题,最终实现整棵树的最大效益。

题目描述:...

解法:

    树形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 }

转载于:https://www.cnblogs.com/silver-bullet/archive/2012/10/29/2745400.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值