一些专题上的题目总结
Posted pandaking
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一些专题上的题目总结相关的知识,希望对你有一定的参考价值。
感觉其实cf c,d级别的树形dp其实没有那么的复杂,主要是要搞清楚一点,怎么利用子树去更新父节点,然后就还是想清楚问题和状态呀!
codeforces682c
题意:在一棵树上存在这样一个种节点 u 。满足u存在v的子树中,(u,v)的之间的边权和大于a[u]的话,那么u点是不开心的。你只能从叶子节点开始删除点,问你最少删除多少个点,可以使得这个树里面没有不开心的点。
首先这道题目是从根节点出发,然后u,v的边权和大于a[u],那么u是不开心,就要去掉,我们可以保存一个变量,存到纬度里面去,保存从根节点到u上这条链上边权和最大的值,如果大于,则这颗子树都不要了,否则就返回已经在子树中计算的答案。
就是dfs即可
代码:
1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <cmath> 6 #include <vector> 7 #include <bitset> 8 typedef long long ll; 9 using namespace std; 10 const int maxn=100100; 11 int n; 12 ll ai[maxn]; 13 int size[maxn]; 14 struct node{ 15 int to; 16 ll ci; 17 node(int a,ll b):to(a),ci(b){}; 18 }; 19 vector<node> G[maxn]; 20 21 void dfs1(int u,int fa){ 22 size[u]=1; 23 for(int i=0;i<G[u].size();i++){ 24 int v=G[u][i].to; 25 if(v==fa) continue; 26 dfs1(v,u); 27 size[u]+=size[v]; 28 } 29 } 30 31 int dfs2(int u,int fa,ll sum){ 32 int ans=0; 33 for(int i=0;i<G[u].size();i++){ 34 int v=G[u][i].to; 35 ll w=G[u][i].ci; 36 if(v==fa) continue; 37 ans+=dfs2(v,u,max(sum+w,w)); 38 } 39 if(sum>ai[u]) return size[u]; 40 else return ans; 41 } 42 43 int main(){ 44 while(scanf("%d",&n)!=EOF){ 45 for(int i=1;i<=n;i++) scanf("%lld",&ai[i]); 46 for(int i=2;i<=n;i++){ 47 int a; 48 ll b; 49 scanf("%d%lld",&a,&b); 50 G[a].push_back(node(i,b)); 51 G[i].push_back(node(a,b)); 52 } 53 dfs1(1,-1); 54 printf("%d ",dfs2(1,-1,0)); 55 } 56 return 0; 57 }
poj-2152 这道题可以说是一道好题了。
题目大意:有N座城市,要求在这N座城市中建一个消防系统,使得每座城市城市着火时都能被按时扑灭
现在给出每座城市建一个消防站所需的花费w和每座城市相邻消防站的最远距离lim(和该城市距离超过lim的城市的消防站无法救该城市的火),问要使所有的城市都能被救到火,建消防站的最小花费是多少
首先我们可以这样设置状态,考虑某个节点,假如这个节点能被消火,那么有这几种可能,1是这个消防站建立在这个城市,2是建立在这个城市的子节点,3是建立在这个城市的父节点。
那么不妨可以这样设置状态,设置dp[u][i] 为以节点u为根节点的子树然后第i个城市控制u节点的最小花费。
那么dp[u][i]肯定是要从各个子树上面获取信息的。这样的话我们可以保存一个cost[v],表示子树的最优选择,但是存在一中情况,子树也可以被i所覆盖,那么这样就会导致重复计算,那么这样的话我们就可以这样变一下,取min(cost[v],dp[v][i]-ai[i])+ai[i],这样就可以排除子树会被城市i所控制的情况
这样通过不断统计子树的信息最后便可以解决整个题目。
下面是代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <bitset> 6 #include <vector> 7 #include <cmath> 8 typedef long long ll; 9 using namespace std; 10 const int maxn=1100; 11 int t,n; 12 struct node{ 13 int to,w; 14 node(int a,int b):to(a),w(b){}; 15 }; 16 int w[maxn],d[maxn],dis[maxn],cost[maxn],dp[maxn][maxn]; 17 vector<node> G[maxn]; 18 19 void Dfs(int u,int fa){ 20 for(int i=0;i<G[u].size();i++){ 21 int v=G[u][i].to; 22 int l=G[u][i].w; 23 if(v==fa) continue; 24 dis[v]=dis[u]+l; 25 Dfs(v,u); 26 } 27 } 28 29 void dfs(int u,int fa){ 30 for(int i=0;i<G[u].size();i++){ 31 int v=G[u][i].to; 32 if(v==fa) continue; 33 dfs(v,u); 34 } 35 dis[u]=0; 36 Dfs(u,-1); 37 for(int i=1;i<=n;i++){ 38 if(dis[i]<=d[u]){ 39 dp[u][i]=w[i]; 40 for(int j=0;j<G[u].size();j++){ 41 int v=G[u][j].to; 42 if(v==fa) continue; 43 dp[u][i]+=min(cost[v],dp[v][i]-w[i]); 44 } 45 cost[u]=min(cost[u],dp[u][i]); 46 } 47 } 48 } 49 50 int main(){ 51 scanf("%d",&t); 52 while(t--){ 53 scanf("%d",&n); 54 for(int i=1;i<=n;i++) scanf("%d",&w[i]); 55 for(int i=1;i<=n;i++) scanf("%d",&d[i]); 56 for(int i=1;i<=n;i++) G[i].clear(); 57 for(int i=1;i<n;i++){ 58 int u,v,l; 59 scanf("%d%d%d",&u,&v,&l); 60 G[u].push_back(node(v,l)); 61 G[v].push_back(node(u,l)); 62 } 63 memset(dp,0x3f,sizeof(dp)); 64 memset(cost,0x3f,sizeof(cost)); 65 dfs(1,-1); 66 printf("%d ",cost[1]); 67 } 68 return 0; 69 }
ps:(其实没有这么难想,感觉只要第一纬是设以u为根的子树,那么自然而然的就想到了,怎么控制这颗子树了。。。。。。。。。。。。。。。。。
以上是关于一些专题上的题目总结的主要内容,如果未能解决你的问题,请参考以下文章