Codeforces 682C Alyona and the Tree(树形DP)

题目大概说给一棵点有权、边也有权的树。一个结点v不高兴当且仅当存在一个其子树上的结点u,使得v到u路径上的边权和大于u的权值。现在要不断地删除叶子结点使得所有结点都高兴,问最少删几个叶子结点。

一开始题目看错了,以为说的是v到u路径上的边权和小于v的权值,然后想出了个解法:从根开始DFS,找高兴的结点,递归过程中在set插入各个祖先结权值,递归返回时从set中删除,而如果set里面最小的元素小于当前结点的路径和那么这个结点就不能要直接return,另外还用到一个简单的数学原理——两个数同时加上相同的数其大小关系不变。。时间复杂度O(nlogn)。

然后写好后才发现读错题。而事实上这题反而更容易。。同样也是从根开始DFS,遇到不高兴的就不往下DFS了,而判断是否高兴就用到个简单的DP了:

  • dp[u]表示祖先到u结点中的最大边权和
  • 由于边权可以为负,所以转移就是dp[v]=max(dp[u]+weight(u,v),weight(u,v))
  • 而u结点不高兴,当且仅当d[u]>weight(u)

另外可以不用long long,这个是没问题的。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define MAXN 111111
 6 struct Edge{
 7     int v,w,next;
 8 }edge[MAXN<<1];
 9 int NE,head[MAXN];
10 void addEdge(int u,int v,int w){
11     edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
12     head[u]=NE++;
13 }
14 
15 int val[MAXN],ans;
16 int d[MAXN];
17 void dfs(int u){
18     if(u!=1 && d[u]>val[u]){
19         return;
20     }
21     ++ans;
22     for(int i=head[u]; i!=-1; i=edge[i].next){
23         int v=edge[i].v;
24         d[v]=max(d[u]+edge[i].w,edge[i].w);
25         dfs(v);
26     }
27 }
28 int main(){
29     int n;
30     scanf("%d",&n);
31     for(int i=1; i<=n; ++i){
32         scanf("%d",val+i);
33     }
34     NE=0;
35     memset(head,-1,sizeof(head));
36     int a,b;
37     for(int i=2; i<=n; ++i){
38         scanf("%d%d",&a,&b);
39         addEdge(a,i,b);
40     }
41     dfs(1);
42     printf("%d",n-ans);
43     return 0;
44 }

 

转载于:https://www.cnblogs.com/WABoss/p/5662863.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值