Codeforces Round #419 (Div. 2) E. Karen and Supermarket(树形dp)

http://codeforces.com/contest/816/problem/E

题意:

去超市买东西,共有m块钱,每件商品有优惠卷可用,前提是xi商品的优惠券被用。问最多能买多少件商品?

 

思路:

第一件商品使用优惠券不需要前提,别的都是需要的,然后这样就形成了一棵以1为根的树。

这样,很容易想到是树形dp。

d【u】【j】【0/1】表示以u为根的子数中选择j件商品所需的最少花费,0/1表示u商品是否能用优惠券。

 

解释一下代码中的sz【】,它所代表的是以u为根的子树的结点数。

当我们现在访问的是1号结点时,sz【1】=1,然后访问2号结点,2号结点访问结束后,我们就会重新回到1号结点的dfs处,然后进行状态转移

 for(int j=sz[u];j>=0;j--)   //表示sz【u】中选取的j个个数

 for(int k=0;k<=sz[v];k++)   //表示v结点及其子树中选取的个数

最后将sz【2】的值加到sz【1】中,这样等下一次进行结点3的状态转移时,只需要考虑在2的子树中选取多少个和3的子树中选取多少个即可。到4时,只需要考虑在2和3中一共选取多少个和4的子树中选取多少个,因为前者在上一步已经计算出了最小花费。

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,int> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn = 5000+5;
17 
18 int n, m;
19 
20 int pa[maxn], pb[maxn];
21 int sz[maxn];
22 int d[maxn][maxn][2];
23 
24 vector<int> g[maxn];
25 
26 void dfs(int u)
27 {
28     sz[u]=1;
29     d[u][0][0]=0, d[u][1][0]=pa[u], d[u][1][1]=pa[u]-pb[u];
30     for(int i=0;i<g[u].size();i++)
31     {
32         int v=g[u][i];
33         dfs(v);
34 
35         for(int j=sz[u];j>=0;j--)
36         {
37             for(int k=0;k<=sz[v];k++)
38             {
39                 d[u][j+k][0]=min(d[u][j+k][0],d[u][j][0]+d[v][k][0]);
40                 d[u][j+k][1]=min(d[u][j+k][1],min(d[u][j][1]+d[v][k][1],d[u][j][1]+d[v][k][0]));
41             }
42         }
43         sz[u]+=sz[v];
44     }
45 }
46 
47 int main()
48 {
49     //freopen("in.txt","r",stdin);
50     while(~scanf("%d%d",&n, &m))
51     {
52         for(int i=1;i<=n;i++)  g[i].clear();
53         for(int i=1;i<=n;i++)
54         {
55             scanf("%d%d",&pa[i],&pb[i]);
56             if(i>1)
57             {
58                 int x;
59                 scanf("%d",&x);
60                 g[x].push_back(i);
61             }
62         }
63 
64         memset(d,INF,sizeof(d));
65         dfs(1);
66 
67         int i;
68         for(i=0;i<=n;i++)
69         {
70             if(min(d[1][i][0],d[1][i][1])>m)   break;
71         }
72         printf("%d\n",i-1);
73     }
74     return 0;
75 }

 

posted @ 2017-06-27 11:10  Kayden_Cheung  阅读(176)  评论(0编辑  收藏  举报
//目录