树上dp(题单)有做到就加进来

本文介绍了四道涉及树形动态规划和图论问题的算法题目,包括寻找最大舒适度子树、构造孤独树的最小操作次数、解决颜色消除问题以及寻找有向图中最长路径。每道题目的解题思路都结合了递归DFS和状态转移方程,并展示了相应的代码实现,强调了在处理树和图问题时的优化技巧和贪心策略。
摘要由CSDN通过智能技术生成

1.牛客小白月赛45-E第一道接触的树上dp.

题意:给定你一个n个节点的树,你需要在树上选取一个非空连通块,使其舒适度和最大。选择的边和点的舒适度都是舒适度。

代码:

void dfs(int now,int fa){
    dp[now]=a[now];
    for(int i=h[now];~i;i=nx[i]){
        int to=e[i];
        if(to==fa)continue;
        int w=value[i];
        dfs(to,now);
        if(w+dp[to]>0)dp[now]+=w+dp[to];
    }
}

2.牛客小白月赛48-孤独的树

题意:给定一个n个节点的树,每个节点有一个权值,定义孤独的树为任意两个节点的gcd==1,每次操作可以将一个节点除以x,问最小进行多少次操作。

思路:贪心在下面的节点无论如何都要与上面的节点gcd==1,则将他的父节点除以他们的gcd,将更好的机会留给了上面的节点。注意用筛法预处理出每个数的质因子个数。

代码:

//预处理2-N中每个数的质因子数
void init(){
    for(int i=2;i<=N;i++){
        if(!cnt[i]){
            cnt[i]=1;
            //将带有i因子的数加上因子有该因子数的个数数
            for(int j=i+i;j<=N;j+=i){
                int t=j;
                while(t%i==0)cnt[j]++,t/=i;
            }
        }
    }
}
//dp方程
void dfs(int u,int fa){
    for(int i=0;i<v[u].size();i++){
        int to=v[u][i];
        if(to==fa)continue;
        dfs(to,u);
        int g=gcd(val[u],val[to]);
        ans+=cnt[g];
        val[u]/=g;
    }
}

3.codeforces gdut排位赛

Problem - A - Codeforces

题意:给定你一颗树,每个节点可以是黑色或者白色,可以进行两种操作。操作一:将一个节点的颜色改为相反的颜色。操作二:将相同颜色的一个连通块消除。

问最少操作次数能将所有节点消除。

思路:对于任意一个节点有黑色和白色的选择,我们开一个大小为[n][2]的树组,j表示该节点的颜色,然后进行dfs.

状态转移方程为:

//颜色相同则减掉上一步消去的步骤,颜色不相同则直接加上去即可 
          dp[s[u]-'0'][u]+=min(dp[s[u]-'0'][to]-1,dp[!(s[u]-'0')][to]); 
          dp[!(s[u]-'0')][u]+=min(dp[!(s[u]-'0')][to]-1,dp[s[u]-'0'][to]);

代码:

void dfs(int u,int fa)
{
	dp[s[u]-'0'][u]=1;//直接消去 
	dp[!(s[u]-'0')][u]=2;//先变颜色再消去 
	for(int i=h[u];~i;i=nx[i]){
	  	int to=e[i];
	 	if(to==fa) continue;
	  	dfs(to,u);
	  	//颜色相同则减掉上一步消去的步骤,颜色不相同则直接加上去即可 
	  	dp[s[u]-'0'][u]+=min(dp[s[u]-'0'][to]-1,dp[!(s[u]-'0')][to]); 
	  	dp[!(s[u]-'0')][u]+=min(dp[!(s[u]-'0')][to]-1,dp[s[u]-'0'][to]);
	}
} 

4.cf div3 786 G. Remove Directed Edges

Problem - G - Codeforces

题意:给定一个有向无环图,要求你找到最长的一条路径,且这条路径上的所有节点的出边和入边都至少为2(除了出发点入边可以等于1或者0,结束点出边可以等于1或者0)

思路:直接树形dp即可,找出最长的链。

代码:

int dp[N]={0},in[N],out[N];
vector<int> v[N];
void dfs(int u){
   if(dp[u])return;
   dp[u]=1;
   if(out[u]<=1)return;
   for(int i=0;i<v[u].size();i++){
   	  int to=v[u][i];
   	  dfs(to);
   	  if(in[to]>=2)dp[u]=max(dp[u],dp[to]+1);
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值