树形DP

作者: Vincy_ivy | 来源:发表于2019-07-08 22:48 被阅读0次

    树形dp的模板是在做题中总结出来的

    POJ 2342 Anniversary party_边

    树形DP满足自下而上,在dfs处通过递归实现
    与scnuoj不一样,这题需要找根节点

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define maxi 6010
    using namespace std;
    int n,dp[maxi][2],book[maxi];
    vector<int>  G[maxi];
    
    void dfs(int u){
        for(int i=0;i<G[u].size();i++){
            int to=G[u][i];
            dfs(to);
            dp[u][1]+=dp[to][0];
            dp[u][0]+=max(dp[to][0],dp[to][1]);
        }
    
    }
    
    
    int main()
    {
        freopen("data.txt","r",stdin);
        cin>>n;
        int a,b;
        for(int i=1;i<=n;i++){
            cin>>dp[i][1];
        }
        for(int i=1;i<n;i++){
            cin>>a>>b;
            G[b].push_back(a);
            book[a]=1;//寻找根节点
        }
        cin>>a>>b;
        int root;
        for(int i=1;i<=n;i++){
            if(!book[i]){
                root=i;
                break;
            }
        }
    
        dfs(root);
        cout<<max(dp[root][0],dp[root][1]);
        return 0;
    }
    

     

    洛谷 P2016 战略游戏_边

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define maxi 6010
    using namespace std;
    int n,dp[maxi][2],book[maxi];
    vector<int>  G[maxi];
    
    void dfs(int u){
        dp[u][1]=1;
        for(int i=0;i<G[u].size();i++){
            int to=G[u][i];
            dfs(to);
            dp[u][0]+=dp[to][1];
            dp[u][1]+=min(dp[to][0],dp[to][1]);
        }
    }
    
    
    int main()
    {
        freopen("data.txt","r",stdin);
        cin>>n;
        int a,b,c;
        int root;
        for(int i=1;i<=n;i++){
            cin>>a>>b;
    
            for(int j=0;j<b;j++){
                cin>>c;
                G[a].push_back(c);
                book[c]=1;
            }
        }
        //i从0开始,自行看题
        for(int i=0;i<n;i++){
            if(!book[i]){
                root=i;
                break;
            }
        }
    
        dfs(root);
        cout<<min(dp[root][0],dp[root][1]);
        return 0;
    }
    

     

    POJ 3659 Cell Phone Network_结点

    //#include <bits/stdc++.h>
    #define maxi 100010 
    #define INF 99999999
    using namespace std;
    //dp[i][0] 自己不选,选父亲
    //dp[i][1] 自己不选,选儿子
    //dp[i][2] 选自己 
    vector<int> G[maxi];
    int dp[maxi][3];
    
    void dfs(int u,int f){
        dp[u][0]=0;
        dp[u][1]=0;
        dp[u][2]=1;
        if(G[u].size()==1&&G[u][0]==f){
            //到底了 
            dp[u][1]=INF;
            return ;
        }
        int flag=0,minn=INF,son=0,v;
        for(int i=0;i<G[u].size();i++){
            v=G[u][i];
            //如果是最后一个结点,则不算 
            if(v==f)
                continue;
            dfs(v,u);
            //u是自己,v是子节点 
            dp[u][2]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
            dp[u][0]+=min(dp[v][1],dp[v][2]); 
            if(dp[v][1]<dp[v][2]){
                dp[u][1]+=dp[v][1];
                if(minn>dp[v][2]){
                    minn=dp[v][2];
                    son=dp[v][1];
                }
            }
            else{
                flag=1;
                dp[u][1]+=dp[v][2];
            }
        }
        if(!flag)
            dp[u][1]+=minn-son; 
    } 
    
    int main(){
        int n;
        cin>>n;
        int a,b;
        for(int i=1;i<n;i++){
            cin>>a>>b;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        dfs(1,-1);
        cout<<min(dp[1][1],dp[1][2])<<endl;
        return 0;
    }
    

     

    ZOJ 3201 Tree of Tree_树上DP

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    //#include <bits/stdc++.h>
    #define maxi 110 
    #define INF 99999999
    using namespace std;
    
    vector<int> G[maxi];
    int dp[maxi][maxi],w[maxi],k,vis[maxi];
    
    void dfs(int u,int f){
        dp[u][1]=w[u];
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            //如果是最后一个结点,则不算 
            if(v==f)
                continue;
            dfs(v,u);
            //u是自己,v是子节点 
            for(int j=k;j>=1;j--)
                for(int l=1;l<=j;l++)
                    dp[u][j]=max(dp[u][j],dp[u][l]+dp[v][j-l]);
        }
    } 
    
    int main(){
    //  freopen("data","r",stdin);
        int n;
        while(scanf("%d%d",&n,&k)!=EOF){
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++){
                G[i].clear();
                cin>>w[i];  
            }
            int a,b;
            for(int i=0;i<n-1;i++){
                cin>>a>>b;
                G[a].push_back(b);
                G[b].push_back(a);
            }
    
            dfs(0,-1);
            int res=0;
            for(int i=0;i<n;i++)
                res=max(dp[i][k],res);
            cout<<res<<endl;    
        }
        return 0;
    }
    

     

    洛谷 P2014 选课_线上DP

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    //#include <bits/stdc++.h>
    #define maxi 350 
    #define INF 99999999
    using namespace std;
    
    vector<int> G[maxi];
    int dp[maxi][maxi],k,n,m,w[maxi];
    
    void dfs(int u){
        for(int i=1;i<m;i++)
            dp[u][i]=w[u];
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            dfs(v);
            //增加一个虚构结点,所以是m+1 
            for(int j=m;j>=1;j--)
                for(int l=1;l<=j;l++)
                    dp[u][j]=max(dp[u][j],dp[u][l]+dp[v][j-l]);
        }
    } 
    
    int main(){
    //  freopen("data","r",stdin);
             scanf("%d%d",&n,&m);
            int a,b;
            for(int i=1;i<=n;i++){
                cin>>a>>w[i];
                G[a].push_back(i);
            }
            dfs(0);
            cout<<dp[0][m]<<endl; 
    
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:树形DP

          本文链接:https://www.haomeiwen.com/subject/kegohctx.html