洛谷 P1273 有线电视网

时间:2021-08-13 17:41:50

2016-05-31 13:25:45

题目链接: 洛谷 P1273 有线电视网

题目大意:

  在一棵给定的带权树上取尽量多的叶子节点,使得sigma(val[选择的叶子节点])-sigma(cost[经过的边])>=0

解法:

  树状DP 背包DP

  DP[i][j]表示i号节点为根的子树中选择了j个叶子节点所得到的最大利润

  转移方程

    DP[i][j]=max(DP[i][j],DP[i][j-k]+DP[son][k]-cost[son][i]);

需要注意的地方

  写初始值的时候要注意除了DP[i][0]=0,全部都是-inf

 //有线电视网 (洛谷 No.1273)
//树状DP 背包DP
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=;
int DP[maxn][maxn];
struct edge
{
int to;
int cost;
int next;
edge(){}
edge(int to,int cost,int next):to(to),cost(cost),next(next){}
};
edge n[maxn];
int head[maxn];
int cnt;
void insert(int x,int y,int z)
{
n[++cnt]=edge(y,z,head[x]);
head[x]=cnt;
return ;
}
int N,M;
int val[maxn];
int DFS(int x)
{
if(x>N-M)
{
DP[x][]=val[x];
return ;
}
int sum=;
for(int i=head[x];i;i=n[i].next)
{
int size=DFS(n[i].to);
sum+=size;
for(int j=sum;j>=;j--)
{
for(int k=;k<=size;k++)
{
DP[x][j]=max(DP[x][j],DP[x][j-k]+DP[n[i].to][k]-n[i].cost);
}
}
}
return sum;
}
int main()
{
scanf("%d %d",&N,&M);
for(int i=;i<maxn;i++)
{
fill(DP[i],DP[i]+maxn,-);
}
for(int i=;i<=N;i++)DP[i][]=;
for(int i=;i<=N-M;i++)
{
int x;
scanf("%d",&x);
for(int j=;j<=x;j++)
{
int to,val;
scanf("%d %d",&to,&val);
insert(i,to,val);
}
}
for(int i=N-M+;i<=N;i++)
{
scanf("%d",&val[i]);
}
DFS();
for(int i=M;i>=;i--)
{
if(DP[][i]>=)
{
printf("%d",i);
return ;
}
}
return ;
}