题意
给一个n个结点的树,每个结点有最大载重m,上面有c[i]朵花,对于每个结点,它的儿子个数和花的朵数不能超过m。现在可以删掉一些结点,每删掉一个,它的花就会给父亲,求最多能删掉多少结点。
解析
树形Dp+贪心。
可以直接Dfs递归实现。
显然从权值小的开始删起。
#include <cstdio>
#include <vector>
#include <algorithm>
#define Rep( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i<=(i##_END);i++)
#define For( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i++)
#define Lop( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i>=(i##_END);i--)
#define Dnt( i , _begin , _end ) for(int i=(_begin),i##_END=(_end);i!=(i##_END);i--)
using std :: min;
using std :: max;
const int maxx = 2000000 + 25;
int c[maxx];
std :: vector <int> G[maxx];
int n,m,x,y,z,ans;
bool cmp(int a,int b) {return c[a] < c[b];}
void Dfs(int x){
For( i , 0 , G[x].size() ) Dfs(G[x][i]);
std :: sort(G[x].begin(),G[x].end(),cmp);
c[x] += G[x].size();
For( i , 0 , G[x].size() ){
int now = c[G[x][i]];
if(c[x] + now - 1 <= m){
c[x] += now - 1;
ans ++;
}
else break;
}
}
int main(){
scanf("%d%d",&n,&m);
For( i , 0 , n ) scanf("%d",&c[i]);
For( i , 0 , n ){
scanf("%d",&x);
while( x-- ){
scanf("%d",&y);
G[i].push_back(y);
}
}
Dfs(0);
printf("%d",ans);
return 0;
}