树形dp--P1273 有线电视网

*传送

*定义状态:

这道题是一道裸的树形背包题,设f[i][j]表示以i 为根往下找j 个叶子的最大价值,那么答案就是所有f[1][j]0当中最大的j

在dp之前,我们按照后序遍历序列重新编号(即遍历到一个节点时,先搜索节点的子树,为它们编号后再为这个节点编号)。

然后开始dp,首先初始化,对f[i][j]赋值INF,当j==0 时f[i][j]=0 。

*状态转移:

如果i点是叶子节点那么有f[i][j]=max(f[i1][j1]+c[i],f[i1][j]) 和一般的0/1背包没什么区别

如果不是的话,如果我们取i的话f[i][j]=f[i1][j]+c[i],但是如果不取的话它和它的子树就一个都不能取了。

而由后序遍历定义不难推出i的子树节点编号在[isz[i]+1,i]之间(sz[i]为子树i的大小)。

所以不取的话f[i][j]=f[isz[i]][j] ,综上f[i][j]=max(f[i1][j]+c[i],f[isz[i]][j])

代码:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 const int N=6000;
 5 const int INF=1e9;
 6 using namespace std;
 7 int read(){
 8     int x = 1,a = 0;
 9     char ch = getchar();
10     while(ch < '0' || ch > '9'){
11         if(ch == '-')x = -1;
12         ch = getchar();
13     }
14      while(ch <= '9'&&ch >= '0'){
15         a = a * 10 + ch - '0';
16         ch = getchar();
17     }
18     return x*a;
19 }
20 struct node{
21     int to,next;
22 }ed[N];
23 int n,m,head[N],tot;
24 void add(int u,int v){//链前 
25     ed[++tot].next=head[u];
26     ed[tot].to=v;
27     head[u]=tot;
28 }
29 int f[N][N],sz[N],idx[N],cnt,c[N];
30 void dfs(int x){
31     sz[x]=1;
32     for (int i = head[x];i;i=ed[i].next){
33         int v=ed[i].to;
34         dfs(v);sz[x]+=sz[v]; //求子树大小 
35     }
36     idx[++cnt]=x;//遍历顺序 
37 }
38 int main(){
39     scanf ("%d%d",&n,&m);
40     for(int i=1;i<=n-m;i++){
41         int k=read();
42         for(int j=1;j<=k;j++){
43             int v=read();c[v]=-read();// 花费为负 
44             add(i,v);//构建树,转播站和能转播到的节点连在一起 
45         }
46     }
47     for(int i=n-m+1;i<=n;i++)c[i]+=read();// 预算为正 
48     dfs(1);
49     for(int i=0;i<=cnt;i++)
50         for(int j=1;j<=m;j++)
51             f[i][j]=-INF;
52     for(int i=1;i<=cnt;i++){
53         int u=idx[i];
54         for(int j=1;j<=m;j++){
55             if(n-m+1<=u)f[i][j]=max(f[i-1][j-1]+c[u],f[i-1][j]);// 是客户(叶子)节点 
56             else f[i][j]=max(f[i-1][j]+c[u],f[i-sz[u]][j]); // 不是客户(叶子)节点 
57         }
58     }
59     for(int i=m;i>=0;i--){
60         if(f[cnt][i]>=0){
61             printf("%d\n",i);return 0;
62         }
63     }
64     return 0;
65 }

猜你喜欢

转载自www.cnblogs.com/very-beginning/p/12651552.html
今日推荐