zoukankan      html  css  js  c++  java
  • [ZJOI 2008] 骑士

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=1040

    [算法]

            首先 , 题目中互相讨厌的关系构成了一棵基环森林 

            用拓扑排序找出环 , 对于每个环上的点为根节点 , 做以下DP :

            f[u][0]表示以u为根的子树中 , 不选u , 最大战斗力是多少 , f[u][1]表示选u , 最大战斗力是多少

            显然 :

            f[u][0] = sigma{max{f[v][0] , f[v][1]})

            f[u][1] = a[u] + sigma{f[v][0]}

            然后在环上再次DP即可

            时间复杂度 : O(N)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 1000010
    typedef long long LL;
    const LL inf = 1e18;
    
    struct edge
    {
            int to , nxt;
    } e[MAXN << 1];
    
    int n , tot , cnt;
    int head[MAXN] , deg[MAXN] , a[MAXN] , c[MAXN];
    LL f[MAXN][2] , dp[MAXN][2];
    bool vis[MAXN];
    LL ans , res;
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v)
    {
            ++tot;
            e[tot] = (edge){v , head[u]};
            head[u] = tot;
    }
    inline void topsort()
    {
            queue< int > q;
            for (int i = 1; i <= n; i++)
            {
                    if (deg[i] == 1)
                            q.push(i);        
            }                
            while (!q.empty())
            {
                    int cur = q.front();
                    q.pop();
                    for (int i = head[cur]; i; i = e[i].nxt)
                    {
                            int v = e[i].to;
                            if ((--deg[v]) == 1)
                                    q.push(v);
                    }
            }
    }
    inline void treedp(int u , int fa)
    {
            f[u][0] = 0;
            f[u][1] = a[u];
            for (int i = head[u]; i; i = e[i].nxt)
            {
                    int v = e[i].to;        
                    if (v == fa || vis[v]) continue;
                    treedp(v , u);
                    f[u][0] += max(f[v][0] , f[v][1]);
                    f[u][1] += f[v][0];
            }        
    }
    inline void dfs(int u)
    {
            c[++cnt] = u;
            vis[u] = true;
            for (int i = head[u]; i; i = e[i].nxt)
            {
                    int v = e[i].to;
                    if (!vis[v] && deg[v] > 1) dfs(v);        
            }        
    } 
    
    int main()
    {
            
            read(n);
            for (int i = 1; i <= n; i++)
            {
                    read(a[i]);
                    int fa;
                    read(fa);
                    addedge(i , fa);
                    addedge(fa , i);    
                    ++deg[i]; ++deg[fa];    
            }
            topsort();
            for (int u = 1; u <= n; u++)
            {
                    if (!vis[u] && deg[u] > 1) 
                    {
                            cnt = 0;
                            dfs(u); 
                    } else continue;
                    for (int i = 1; i <= cnt; i++) treedp(c[i] , -1);
                    ans = max(f[c[1]][0] , f[c[1]][1]);
                    for (int i = 1; i <= cnt; i++) dp[i][0] = dp[i][1] = -inf;
                    dp[1][0] = f[c[1]][0];
                    for (int i = 2; i <= cnt; i++)
                    {
                            dp[i][1] = dp[i - 1][0] + f[c[i]][1];
                            dp[i][0] = max(dp[i - 1][0] , dp[i - 1][1]) + f[c[i]][0];
                    }
                    chkmax(ans , max(dp[cnt][0] , dp[cnt][1]));
                    for (int i = 1; i <= cnt; i++) dp[i][0] = dp[i][1] = -inf;
                    dp[1][1] = f[c[1]][1];
                    for (int i = 2; i < cnt; i++)
                    {
                            dp[i][1] = dp[i - 1][0] + f[c[i]][1];
                            dp[i][0] = max(dp[i - 1][0] , dp[i - 1][1]) + f[c[i]][0];                
                    }
                    chkmax(ans , max(dp[cnt - 1][0] , dp[cnt - 1][1]) + f[c[cnt]][0]);
                    res += ans;
            }
            printf("%lld
    " , res);
            
            return 0;
        
    }
  • 相关阅读:
    征战蓝桥 —— 2015年第六届 —— C/C++A组第5题——九数组分数
    征战蓝桥 —— 2015年第六届 —— C/C++A组第5题——九数组分数
    征战蓝桥 —— 2015年第六届 —— C/C++A组第4题——格子中输出
    SSLZYC 邮票
    SSLZYC 道路阻塞
    SSLZYC 反射
    SSLZYC 家族
    秒杀系统架构分析与实战
    工厂模式
    工厂模式
  • 原文地址:https://www.cnblogs.com/evenbao/p/9925804.html
Copyright © 2011-2022 走看看