• 【算法笔记】树形dp


    ·前言

    树形dp,顾名思义,就是在树上进行的dp,它一般会搭配上深度优先搜索进行,以记录下所以的孩子/父亲的状态用于转移
    (可能会出现一大堆的计数题,感觉这种dp特别适合用来整计数)

    ·基本思维

    树形dp最大的特点就是在一边搜索的时候一边记录答案,这样子的话调用答案的时候会比较方便。而且,当遇到图论题的时候,其实也可以把图转化成一棵树来解决问题。
    比较简单的树形dp思路相对好想,码量也不算大(但是难打的树形dp思路就会特别毒瘤,根本就想不出来啊……

    这里给出一些树形dp比较常用的板子:
    ·树的最大独立集
    #include<bits/stdc++.h>
    using namespace std;
    int n,f[100010][25],g[100010],s[100010],d[100010];
    vector<int>v[100010];
    void dfs(int x,int fa){
        for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1];
        for(int i=0;i<v[x].size();i++){
            int to=v[x][i];
            if(to==fa)continue;
            f[to][0]=x;
            dfs(to,x);
        }
        d[x]=max(s[x],g[x]+1);
        s[f[x][0]]+=d[x];
        g[f[x][1]]+=d[x];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        dfs(1,0);
        printf("%d",d[1]);
        return 0;
    }
    View Code

    ·树的重心

    #include<bits/stdc++.h>
    using namespace std;
    int son[100010],vis[100010],n,size,ans;
    vector<int>v[100010];
    void dfs(int x){
        vis[x]=1;son[x]=0;
        int maxn=0;
        for(int i=0;i<v[x].size();i++){
            int to=v[x][i];
            if(!vis[to]){
                dfs(to);
                son[x]+=son[to]+1;
                maxn=max(maxn,son[to]+1);
            }
        }
        maxn=max(maxn,n-son[x]-1);
        if(maxn<size||maxn==size&&x<ans)ans=x,size=maxn;
    }
    int main(){
        scanf("%d",&n);
        size=1e9;
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        dfs(1);
        printf("%d %d
    ",ans,size);
        return 0;
    
    }
    View Code

    ·树上最长路径

    #include<bits/stdc++.h>
    using namespace std;
    int n,vis[200010],d[200010];
    vector<int>v[200010]; 
    int spfa(int u){
        queue<int>q;
        memset(d,0x3f,sizeof(d));
        memset(vis,0,sizeof(vis));
        q.push(u);
        d[u]=0;vis[u]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=0;i<v[x].size();i++){
                int to=v[x][i];
                if(d[to]>d[x]+1){
                    d[to]=d[x]+1;
                    if(!vis[to]){
                        vis[to]=1;
                        q.push(to);
                    }
                }
            }
            vis[x]=0;
        }
        int maxn=0,id;
        for(int i=1;i<=n;i++)
            if(i!=u){
                if(d[i]>maxn)id=i,maxn=d[i];
            }
        return id;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        int ans=0,id=spfa(1);
        ans+=d[id];
        int ans1=ans,id2=spfa(id);
        if(id==1)ans=max(ans,d[id2]);
        else ans+=d[id2];
        printf("%d
    ",ans-ans1);
        return 0;
    }
    View Code

    ·题目汇总

    poj2342/hdu1520 Anniversary party
    hdu6201 transaction transaction transaction
    hdu2196 Computer
    Luogu2014 CTSC1997
    hdu6035 Colorful Tree
    codeforces 1101D/990G Gcd Counting
    Luogu3177 HAOI2015
    UVA10859 Placing Lampposts
    *先不放链接啦,先把题目放在这里,以后会把代码补上。
  • 相关阅读:
    Selenium2+python自动化6-八种元素元素定位(Firebug和firepath)
    Selenium2+python自动化5-操作浏览器基本方法
    Selenium2+python自动化4-Pycharm使用
    Selenium2+python自动化3-解决pip使用异常
    Selenium2+python自动化2-pip降级selenium3.0
    Selenium2+python自动化1-环境搭建
    由《大宅门》看季宗布的育人之道
    三大线性排序之计数排序
    反转字符串
    out.print和out.write方法
  • 原文地址:https://www.cnblogs.com/linskyQWQ/p/13455723.html
Copyright © 2020-2023  润新知