csu 2014 summer training day 4 树形dp升阶

POJ 1155

题意:电视台发送信号给很多用户,每个用户有愿意出的钱,电视台经过的路线都有一定费用,求电视台不损失的情况下最多给多少用户发送信号。

要知道用户都在叶子节点,费用消耗在使用选择的路径上,每条路径的使用费用给出,每个用户支付的费用给出。

输入:N为总节点数,M为用户数,1为电视台, 2 to N-M 是中转站,N-M+1到N是潜在用户

对于1到N-M的中继点,给出连接的点的个数K,K对(A,C)表示连接到A点,这条路径的费用是C

最后是M个整数,表示用户支付的费用

分析:

int num[maxn];//记录每个节点下面的总用户数
int dp[maxn][maxn];//i:i的子树中,j:节点下面的使用用户数,能达到的最大的剩余利润
//dp:最大剩余利润:线路费用-使用用户支付的费用
相当于树形背包:
dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]);
temp[j]表示原来的dp[u][j]
对于搜索出来的一棵树,对于它的孩子,可以选择加还是不加,其中len[u][i]恰好表示u到当前选择的v的代价

完整写法:
        for(int j=0;j<=num[u];j++){
            temp[j]=dp[u][j];
        }
        for(int j=0;j<=num[u];j++){
            for(int k=1;k<=num[v];k++){//注意k!=0,否则多减少了i
                dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]);
            }
        }
        num[u]+=num[v];

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define maxn 3100
 6 #define INF 99999999
 7 using namespace std;
 8 
 9 int num[maxn];//记录每个节点下面的总用户数
10 int dp[maxn][maxn];//i:处理的节点数,j:节点下面的使用用户数
11 //dp:最大剩余利润:线路费用-使用用户支付的费用
12 int N,M;
13 vector<int>G[maxn];
14 vector<int>len[maxn];
15 int temp[maxn];
16 void dfs(int u,int fa){
17 
18 //    cout<<"u="<<u<<endl;
19 //    for(int i=0;i<G[u].size();i++){
20 //        int v=G[u][i];
21 //        if (v==fa) continue;
22 //        dfs(v);
23 //        num[u]+=num[v];
24 //    }
25 //    //用子节点更新u
26 //    int sum=0;
27 //    for(int i=0;i<G[u].size();i++){//依次枚举下层节点
28 //        int v=G[u][i];
29 //        if (v==fa) continue;
30 //        for(int j=0;j<=sum;j++){//设置这个的原因是,仔细看下面,原本的dp[u][j]已经被覆盖了
31 //            temp[j]=dp[u][j];
32 //        }
33 //        for(int j=0;j<=sum;j++){
34 //            for(int k=0;k<=num[v];k++){
35 //                dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]);
36 //            }
37 //        }
38 //        sum+=num[v];
39 //    }
40 //我们可以看出,上面两部分可以和在一起写,而且每次更新的num[u]就是sum
41 
42     dp[u][0]=0;
43     for(int i=0;i<G[u].size();i++){
44         int v=G[u][i];
45         if (v==fa) continue;
46         dfs(v,u);
47         for(int j=0;j<=num[u];j++){
48             temp[j]=dp[u][j];
49         }
50         for(int j=0;j<=num[u];j++){
51             for(int k=1;k<=num[v];k++){//注意k!=0,否则多减少了i
52                 dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-len[u][i]);
53             }
54         }
55         num[u]+=num[v];
56     }
57     return ;
58 }
59 void solve(){
60     for(int i=M;i>=0;i--){
61         if (dp[1][i]>=0) {
62             printf("%d\n",i);
63             break;
64         }
65     }
66     return ;
67 }
68 int main(){
69     while(~scanf("%d%d",&N,&M)){
70         for(int i=0;i<=N;i++) G[i].clear();
71         for(int i=1;i<=N-M;i++){
72             int k;
73             scanf("%d",&k);
74             for(int j=1;j<=k;j++){
75                 int v,c;
76                 scanf("%d%d",&v,&c);
77                 G[i].push_back(v);
78                 len[i].push_back(c);
79             }
80         }
81         memset(num,0,sizeof(num));
82         for(int i=0;i<=N;i++){
83             for(int j=0;j<=N;j++) dp[i][j]=-INF;
84         }
85         for(int i=N-M+1;i<=N;i++){
86             scanf("%d",&dp[i][1]);
87             num[i]=1;
88         }
89         dfs(1,-1);
90         solve();
91     }
92     return 0;
93 }
View Code

 

POJ 2486

题意:Wshxzt从根节点1开始在苹果树上游历,树上的每个节点都会存在apple[i]个苹果,从一个节点到它的邻节点耗费步数1。现在Wshxzt可以步行step步,求她可以得到的最大苹果数量。

输入:N节点数,K最大步数,每个节点的苹果数,N-1条边

分析:

代码:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<vector>
 5 #define MAXN 110
 6 #define MAXK 220
 7 using namespace std;
 8 
 9 vector<int>G[MAXN];
10 int anum[MAXN];
11 int dp[MAXN][MAXK][2];
12 int N,K;
13 int temp[MAXN];
14 void dfs(int u,int fa){
15     dp[u][0][1]=anum[u];
16     dp[u][0][0]=anum[u];
17     for(int i=0;i<G[u].size();i++){
18         int v=G[u][i];
19         if (v==fa) {
20             continue;
21         }
22         dfs(v,u);
23         for(int j=K;j>=0;j--){
24             for(int t=1;t<=j;t++){
25                 dp[u][j][0]=max(dp[u][j][0],dp[v][t-1][0]+dp[u][j-t][1]);
26                 if (t==1) continue;
27                 dp[u][j][0]=max(dp[u][j][0],dp[v][t-2][1]+dp[u][j-t][0]);
28                 dp[u][j][1]=max(dp[u][j][1],dp[v][t-2][1]+dp[u][j-t][1]);
29             }
30         }
31     }
32 
33     return ;
34 }
35 int main(){
36     while(~scanf("%d%d",&N,&K)){
37         for(int i=1;i<=N;i++){
38             scanf("%d",&anum[i]);
39         }
40         for(int i=0;i<=N;i++) G[i].clear();
41         for(int i=1;i<=N-1;i++){
42             int u,v;
43             scanf("%d%d",&u,&v);
44             G[u].push_back(v);
45             G[v].push_back(u);
46         }
47         memset(dp,0,sizeof(dp));
48         for(int i=0;i<=N;i++){
49             for(int j=0;j<=K;j++) dp[i][j][0]=dp[i][j][1]=anum[i];
50         }
51         dfs(1,-1);
52         printf("%d\n",dp[1][K][0]);
53     }
54     return 0;
55 }
View Code

 

POJ 1947

 

 

POJ 1848

 

 

 

POJ 1655

posted @ 2014-07-28 18:00  little_w  阅读(177)  评论(0编辑  收藏  举报