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 ",i-1); 73 } 74 return 0; 75 }