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
1 //有线电视网 (洛谷 No.1273) 2 //树状DP 背包DP 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=3010; 7 int DP[maxn][maxn]; 8 struct edge 9 { 10 int to; 11 int cost; 12 int next; 13 edge(){} 14 edge(int to,int cost,int next):to(to),cost(cost),next(next){} 15 }; 16 edge n[maxn]; 17 int head[maxn]; 18 int cnt; 19 void insert(int x,int y,int z) 20 { 21 n[++cnt]=edge(y,z,head[x]); 22 head[x]=cnt; 23 return ; 24 } 25 int N,M; 26 int val[maxn]; 27 int DFS(int x) 28 { 29 if(x>N-M) 30 { 31 DP[x][1]=val[x]; 32 return 1; 33 } 34 int sum=0; 35 for(int i=head[x];i;i=n[i].next) 36 { 37 int size=DFS(n[i].to); 38 sum+=size; 39 for(int j=sum;j>=0;j--) 40 { 41 for(int k=1;k<=size;k++) 42 { 43 DP[x][j]=max(DP[x][j],DP[x][j-k]+DP[n[i].to][k]-n[i].cost); 44 } 45 } 46 } 47 return sum; 48 } 49 int main() 50 { 51 scanf("%d %d",&N,&M); 52 for(int i=0;i<maxn;i++) 53 { 54 fill(DP[i],DP[i]+maxn,-1000000); 55 } 56 for(int i=1;i<=N;i++)DP[i][0]=0; 57 for(int i=1;i<=N-M;i++) 58 { 59 int x; 60 scanf("%d",&x); 61 for(int j=1;j<=x;j++) 62 { 63 int to,val; 64 scanf("%d %d",&to,&val); 65 insert(i,to,val); 66 } 67 } 68 for(int i=N-M+1;i<=N;i++) 69 { 70 scanf("%d",&val[i]); 71 } 72 DFS(1); 73 for(int i=M;i>=0;i--) 74 { 75 if(DP[1][i]>=0) 76 { 77 printf("%d",i); 78 return 0; 79 } 80 } 81 return 0; 82 }
时间: 2024-11-05 19:00:58