• ZOJ_2834 树形DP


    题目意思太罗嗦,不解释了。这道题一开始一直Segmentation Fault,问了秦总才发现可能是数组放在dfs里面的关心后来又wa了无数次,结果是因为它居然可以是个森林!!!简直报警了,题目中明明说的是Koopa的所有儿子,居然还可以存在森林。唉。。。

    这道题好事蛮不错的一道题,每一个点有三种状态:dp[i][0],dp[i][1],dp[i][2]。dp[i][1]代表第i个人刚刚被干掉,第i个节点及其子树的最大值。dp[i][0]代表第i个节点即所有节点的t[i]值之和。dp[i][2]代表的是第i个节点没有被干掉所能干掉其子树的最大值和。

    下面来写转移方程:

    dp[u][0] = t[u] + sum{dp[v][0]};

    dp[u][2] = max{dp[v][0] + sum{dp[w][2] | w != v} = max{dp[v][0]-dp[v][2])}+ sum{dp[v][2]}; 这两个v相互独立

    dp[u][1] = max{dp[v][0]-dp[v][2] + dp[w][1] - dp[w][2] | w != v} + sum{dp[v][2]};

    注意下一边界条件就可以开始写了。。。算 dp[v][0]-dp[v][2]+dp[w][1]-dp[w][2]的最大值的时候有一个小技巧,直接看我的代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #define FOR(i,x,y) for(int i = x;i < y;i ++)
    
    using namespace std;
    
    const int MAXN = 2222;
    
    int n,dp[MAXN][3],t[MAXN],head[MAXN],edge_cnt;    //dp[i][0]表示i个节点和他的所有子树都被杀了,dp[i][1]表示第一次i个节点被杀了,dp[i][2]表示i个节点没被杀
    int st[MAXN];
    
    struct Edge{
        int to,next;
    }edge[MAXN<<1];
    
    bool cmp(int x,int y)   {return x>y;}
    
    void add_edge(int u,int v){
        edge[edge_cnt].to = v;
        edge[edge_cnt].next = head[u];
        head[u] = edge_cnt++;
    }
    
    void dfs(int u,int fa){
        dp[u][0] = dp[u][1] = t[u]; dp[u][2] = 0;
        int cnt = 0;
        int dp2 = -1;
        int sum = 0;
        int dp00 = -1,dp01 = -1,dp10 = -1,dp11 = -1; ///dp00 代表dp[v][0]-dp[v][2]的最大值,dp01代表第二大值,dp10同理
        for(int i = head[u];i != -1;i = edge[i].next){
            int v = edge[i].to;
            if(v == fa) continue;
            dfs(v,u);
            dp[u][0] += dp[v][0];
            sum += dp[v][2];
            if((dp[v][0]-dp[v][2]) >= dp00){
                dp01 = dp00;
                dp00 = dp[v][0]-dp[v][2];
            }
            else dp01 = max(dp01,t[v]);
            if(dp[v][1]-dp[v][2] >= dp10){
                dp11 = dp10;
                dp10 = dp[v][1]-dp[v][2];
            }
            else dp11 = max(dp11,dp[v][1]-dp[v][2]);
            dp2 = max(dp2,dp[v][0]-dp[v][2]+dp[v][1]-dp[v][2]);
            cnt++;
        }
        if(!cnt)    return;
        if(cnt == 1){
            dp[u][1] += sum+dp00;
            dp[u][2] += sum+dp00;
        }
        else{
            if(dp00 + dp10 == dp2) {
                if(dp01 == dp00 || dp11 == dp10)
                    dp[u][1] += sum+dp2;
                else
                    dp[u][1] += sum+max(dp00+dp11,dp01+dp10);
            }
            else
                dp[u][1] += sum + dp00 + dp10;
            dp[u][2] += sum+dp00;
        }
        return;
    }
    
    int dfs2(int u,int fa){
        int ans = t[u];
        for(int i = head[u];i != -1;i = edge[i].next){
            int v = edge[i].to;
            if(v == fa) continue;
            ans += dfs2(v,u);
        }
        return ans;
    }
    
    int main()
    {
        freopen("test.in","r",stdin);
        while(~scanf("%d",&n) && n){
            memset(head,-1,sizeof(head));
            edge_cnt =0;
            FOR(i,0,n)  scanf("%d",&t[i]);
            int to;
            int st_cnt = 0;
            FOR(i,0,n){
                scanf("%d",&to);
                if(to == -1){
                    st[st_cnt++] = i;
                    continue;
                }
                add_edge(i,to);
                add_edge(to,i);
            }
            int ans = 0;
            FOR(i,0,st_cnt-1)   ans += dfs2(st[i],-1);
            dfs(n-1,-1);
            printf("%d
    ",ans+dp[n-1][1]);
        }
        return 0;
    }
    


  • 相关阅读:
    iOS BUG整理-记录我近期视频开发遇到的问题
    iOS 翻译-UIWebView的基本简介-官方文档翻译
    iOS 翻译-Xcode使用-文档翻译
    4.redis设计与实现--跳跃表
    3.redis设计与实现--字典
    2.redis设计与实现--链表
    1.redis设计与实现--简单动态字符串
    12.编码问题讨论
    11.nginx upload module + python django 后台 实现视频上传与切片
    10.nginx+ffmpeg上搭建HLS切片
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4555876.html
Copyright © 2020-2023  润新知