树形dp解法

二叉树的直径

将一棵树抽象成左子树,右子树,根节点,求出左子树作为根的最长链长度l,右子树作为根的最长链长度r,则其父节点的最长链长度为max(l,r)+1

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int ans=0;
    int dfs(TreeNode*node)//返回以当前节点为根的最长链
    {
        if(node==nullptr)
        return -1;
        int l_len=dfs(node->left);
        int r_len=dfs(node->right);
        ans=max(ans,l_len+r_len+2);
        return max(l_len,r_len)+1;
    }
    int diameterOfBinaryTree(TreeNode* root) {
        dfs(root);
        return ans;
    }
};

最大路径和

也是求出左右子树的最大路径和lsum,和rsum,而父节点的最大路径和就为max(lsum,rsum)+node->val,而空节点返回0.还有一点要注意的是如果父节点求出的最大路径和为负数,那他对最终的总和的贡献为负,可以直接不选,返回0即可

class Solution {
public:
    int ans=-1000000000;
    int dfs(TreeNode*node)
    {
        if(node==nullptr)
            return 0;
        int lsum=dfs(node->left);
        int rsum=dfs(node->right);
        ans=max(ans,lsum+rsum+node->val);
        return max(max(lsum,rsum)+node->val,0);
    }
    int maxPathSum(TreeNode* root) {
        dfs(root);
        return ans;
    }
};

打家劫舍3

这题可分偷根节点和不偷根节点两种情况,如果偷根节点,那它的两个儿子都不能偷,如果不偷根节点,那它的两个儿子偷与不偷均可

class Solution {
public:
    pair dfs(TreeNode*node)
    {
        if(node==nullptr)
        return {0,0};
        auto[lrob,lnrob]=dfs(node->left);
        auto[rrob,rnrob]=dfs(node->right);
        int rob=lnrob+rnrob+node->val;
        int nrob=max(lnrob,lrob)+max(rnrob,rrob);
        return {rob,nrob};
    }
    int rob(TreeNode* root) {
        auto[l,r]=dfs(root);
        return max(l,r);
    }
};

相邻字符不同的最长路径

树形dp解法_第1张图片 

class Solution {
public:
    int ans=0;
    vectorg[100005];
    int dfs(int x,int pr,string&s)
    {
        int maxlen=0;
        for(auto y:g[x])
        {
            if(y==pr)continue;
            int len=dfs(y,x,s)+1;
            if(s[y]!=s[x])
            {
                ans=max(ans,maxlen+len);
                maxlen=max(maxlen,len);
            }
        }
        return maxlen;
    }
    int longestPath(vector& parent, string s) {
        int n=parent.size();
        for(int i=1;i

没有上司的舞会

这题是打家劫舍3的升级版,不再是二叉树,而是一般的树,要做这一题,你得先学会建树,你可以采用建图的的方法建树(邻接表法),然后你要了解树形dp的基本模版,这个题与打家劫舍的思路一样,不同的是,一个节点可能有多个儿子,根节点不选=求和(max(儿子选,儿子不选)),根节点选=求和(儿子不选),你可以用一个vector保留本层的儿子的结果,再根据儿子的结果,求出当且节点(父节点)的结果,再return

#include//选=求和(不选) 不选等于求和(max(选,不选))
using namespace std;
#define int long long
vectorg[6005];//邻接表储存树
pairdfs(int x,int pr,vector&v)
{
    vector>que;
    for(auto i:g[x])
    {
        if(i==pr)continue;//遍历到父节点,跳过此次循环
        pairp=dfs(i,x,v);//得到每个儿子选和不选的结果
        que.push_back(p);
    }
    int rob=0,nrob=0;
    for(int i=0;i>n;
    vectorv(n+1);//快乐指数
    for(int i=1;i<=n;i++)cin>>v[i];
    for(int i=0;i>l>>k;
        g[l].push_back(k);
        g[k].push_back(l);
    }
    auto[lrob,rrob]=dfs(1,-1,v);//求得根节点选和不选的情况
    cout<

你可能感兴趣的:(深度优先,算法)