[树形dp]
作者:互联网
链接:https://ac.nowcoder.com/acm/problem/13249
来源:牛客网
题目描述
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。 输入描述:
第一行一个整数n (1 ≤ n ≤ 10^5) 接下来n-1行,每行一个整数,依次为2号点到n号点父亲的编号。 最后一行n个整数为k[i] (1 ≤ k[i] ≤ 10^5) 样例解释: 对节点3操作,导致节点2与节点3变黑 对节点4操作,导致节点4变黑 对节点1操作,导致节点1变黑
输出描述:
一个数表示最少操作次数示例1 输入
4 1 2 1 1 2 2 1
输出
3
题意:给出一棵树,根节点编号为1,每个节点有一个权值ai表示从该节点向上距离不超过ai的点都可以被染色,求要使所有点被染色需要的最少操作次数
题解:容易想到dfs到叶子节点,叶子节点必须染色,然后在叶子结点以上被染过的点中找能染到的最小深度,以此向上染色操作次数最少,具体实现过程:递归地用dp[u]表示该节点或者该节点以下节点能染到的
最小深度,在已经被染色的点的尽头,也就是第一个未被染色的点A处ans+1,同时更新染色尽头为dp[A]即可,这里使用了数组pos记录染色尽头以便更新答案
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 //#define io_test 10 #define debug(x) cout<<x<<"####"<<endl; 11 typedef long long ll; 12 int rod[100005]; 13 const int inf=0x3f3f3f3f; 14 struct edge{ 15 int y; 16 int nex; 17 }e[100005]; 18 int head[100005],cnt,dep[100005],dp[100005],pos[100005]; 19 void adde(int x1,int y1){ 20 e[cnt].y=y1; 21 e[cnt].nex=head[x1]; 22 head[x1]=cnt++; 23 } 24 int cnt0=0; 25 void dfs(int u,int pre){ 26 dep[u]=dep[pre]+1; 27 dp[u]=dep[u]-rod[u]+1; 28 pos[u]=inf; 29 for(int i=head[u];i!=-1;i=e[i].nex){ 30 int v=e[i].y; 31 dfs(v,u); 32 dp[u]=min(dp[u],dp[v]); 33 pos[u]=min(pos[u],pos[v]); 34 } 35 if(pos[u]>dep[u]){ 36 cnt0++; 37 pos[u]=dp[u]; 38 } 39 } 40 int main() 41 { 42 #ifdef io_test 43 freopen("in.txt","r",stdin); 44 freopen("out.txt","w",stdout); 45 #endif // io_test 46 int n; 47 scanf("%d",&n); 48 memset(head,-1,sizeof(head)); 49 for(int i=2;i<=n;i++){ 50 int a; 51 scanf("%d",&a); 52 adde(a,i); 53 } 54 for(int i=1;i<=n;i++)scanf("%d",&rod[i]); 55 dep[0]=1; 56 dfs(1,0); 57 printf("%d\n",cnt0); 58 return 0; 59 }View Code
标签:变黑,染色,树形,操作,include,节点,dp 来源: https://www.cnblogs.com/MekakuCityActor/p/10682949.html