题意:给定一棵树,树的边带负权,树的叶子带正权,求一棵子树,要求涵盖尽可能多的叶子,同时保证总权值不为负

题解:树形DP,dp[i][j]代表以i为根的子树含有j个叶子结点时最大权值,对每一个i的子树,dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]-c)

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 using namespace std;
 6 const int N=3005,inf=1<<29;
 7 int head[N],nc,n,m,dp[N][N],val[N],num[N];
 8 bool vis[N];
 9 struct Edge
10 {
11     int to,cost,next;
12 } edge[2000000];
13 void add(int a,int b,int c)
14 {
15     edge[nc].to=b;
16     edge[nc].next=head[a];
17     edge[nc].cost=c;
18     head[a]=nc++;
19 }
20 void dfs(int now)
21 {
22     if(head[now]==-1)
23     {
24         if(now>n-m)
25         {
26             num[now]=1;
27             dp[now][0]=0;
28             dp[now][1]=val[now];
29         }
30         else
31         {
32             dp[now][num[now]=0]=0;
33         }
34         return;
35     }
36     else
37     {
38         num[now]=0;
39         dp[now][0]=0;
40         for(int i=head[now]; i!=-1; i=edge[i].next)
41         {
42             int t=edge[i].to,c=edge[i].cost;
43             dfs(t);
44             int tp=num[now]+num[t];
45             for(int j=num[now]+1; j<=tp; j++)
46                 dp[now][j]=-inf;
47             num[now]=tp;
48             tp=num[t];
49             for(int j=num[now]; j>=0; j--)
50             {
51                 for(int k=1; k<=tp&&k<=j; k++)
52                 {
53                     if(dp[now][j-k]!=-inf)
54                         dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[t][k]-c);
55 
56                 }
57             }
58         }
59     }
60 }
61 int main()
62 {
63     //freopen("data.txt","r",stdin);
64     while(scanf("%d%d",&n,&m)!=EOF)
65     {
66         memset(val,0,sizeof(val));
67         memset(head,-1,sizeof(head));
68         nc=0;
69         int nu=n-m;
70         for(int i=1; i<=nu; i++)
71         {
72             int k,a,c;
73             scanf("%d",&k);
74             for(int j=0; j<k; j++)
75             {
76                 scanf("%d%d",&a,&c);
77                 add(i,a,c);
78             }
79         }
80         for(int i=nu+1; i<=n; i++)
81             scanf("%d",&val[i]);
82         memset(dp,0,sizeof(dp));
83         dfs(1);
84         for(int i=num[1]; i>=0; i--)
85         {
86             if(dp[1][i]>=0)
87             {
88                 printf("%d\n",i);
89                 break;
90             }
91         }
92     }
93     return 0;
94 }