[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;
    
}
原文地址:https://www.cnblogs.com/evenbao/p/9925804.html