题目链接:http://poj.org/problem?id=1155

好长时间没写过树形DP了,突然间想写道题,就在网上随便搜了一题。

题目大意:

要转播一场球赛,根节点和所有中转节点都有一个信号塔可以传播信号,所有的叶子节点表示用户。

每条边都有一个权值,表示传播过来需要的花费。

当能传到用户的时候,用户会付一定的费用,问在不亏本的情况下,最多能让几个用户观看到这场球赛。

思路:

用一个DP[u][j]表示以u为根的子树,满足j个用户的时候最多能盈利多少。

那最后找一个最大的j满足DP[1][j]>=0 就是所求。

状态转移:

如果v为u的一个孩子节点。

那么DP[u][i]=Max(DP[u][i] ,  DP[v][j] + DP[u][i-j] - 它们相连的那条边的权值 )

i <= sum[u] ,sum[u]表示当前已枚举到的u下面叶子节点的个数。

j<=sum[v] ,sum[v]表示v下面叶子节点的个数

code:

View Code
 1 # include<stdio.h>
 2 # include<string.h>
 3 # include<stdlib.h>
 4 # define N 3005
 5 # define INF 0xfffffff
 6 struct node{
 7     int from,to,next,val;
 8 }edge[2*N];
 9 int head[N],tol,V[N],DP[N][N],sum[N];
10 void add(int a,int b,int c)
11 {
12     edge[tol].from=a;edge[tol].to=b;edge[tol].val=c;edge[tol].next=head[a];head[a]=tol++;
13 }
14 int Max(int a,int b)
15 {
16     return a>b?a:b;
17 }
18 void dfs(int u,int father)
19 {
20     int i,j,k,v;
21     for(j=head[u];j!=-1;j=edge[j].next)
22     {
23         v=edge[j].to;
24         if(v==father) continue;
25         dfs(v,u);
26         sum[u]+=sum[v];
27         for(i=sum[u];i>=1;i--)               ///sum[u]表示已枚举到的u下面叶子节点的个数,一定要倒序枚举,不然会出现什么错误 (╯▽╰) 
28         for(k=1;k<=sum[v] && k<=i;k++)       ///sum[v]表示v下面叶子节点的个数 
29         DP[u][i]=Max(DP[u][i],DP[v][k]+DP[u][i-k]-edge[j].val);
30     }
31 }
32 int main()
33 {
34     int i,j,n,m,num,ai,ci;
35     while(scanf("%d%d",&n,&m)!=EOF)
36     {
37         tol=0;
38         memset(head,-1,sizeof(head));
39         for(i=1;i<=n-m;i++)
40         {
41             scanf("%d",&num);
42             while(num--)
43             {
44                 scanf("%d%d",&ai,&ci);
45                 add(i,ai,ci);
46                 add(ai,i,ci);
47             }
48         }
49         for(i=n-m+1;i<=n;i++)
50         scanf("%d",&V[i]);
51     memset(sum,0,sizeof(sum));    
52     
53     for(i=0;i<=n;i++)
54     {
55         DP[i][0]=0;
56     for(j=1;j<=n;j++)
57     DP[i][j]=-INF;
58     }
59     
60     for(i=n-m+1;i<=n;i++)
61     {
62     sum[i]=1;
63     DP[i][1]=V[i];
64     }
65 
66     dfs(1,0);
67 
68         for(i=m;i>=0;i--)
69     if(DP[1][i]>=0) break;
70     printf("%d\n",i);
71 }
72     return 0;
73 }

 

posted on 2012-04-27 10:56  奋斗青春  阅读(1022)  评论(0编辑  收藏  举报