[ZJOI2008]骑士

Posted Elder_Giang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZJOI2008]骑士相关的知识,希望对你有一定的参考价值。

1040: [ZJOI2008]骑士

Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 5056  Solved: 1935 [Submit][Status][Discuss]

Description

  Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各 界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境 中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一 个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一 些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出 征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有 的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的 情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战 斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

Input

  第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力 和他最痛恨的骑士。

Output

  应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

Sample Input

3
10 2
20 3
30 1

Sample Output

30

HINT

N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。

题意为在基环树上选点,相邻的两个点不能同时选,求能选出的最大点权
如果是在树上做,设$f[i][0]$表示$i$不选,以$i$为根的子树中能选出的最大值,$f[i][1]$表示$i$选,以$i$为根的子树中能选出的最大值,转移很显然
基环树可以选择拆环,删掉环上的任意一条边,然后枚举两边的点哪个不取,dp即可
#include <cstdio>
#include <algorithm>
using namespace std;
inline int readint(){
    int n = 0;
    char ch = getchar();
    while(ch < 0 || ch > 9) ch = getchar();
    while(ch <= 9 && ch >= 0){
        n = (n << 1) + (n << 3) + ch - 0;
        ch = getchar();
    }
    return n;
}
const int maxn = 1000000 + 10;
struct Edge{
    int to, next;
    bool ok;
    Edge(){}
    Edge(int _t, int _n): to(_t), next(_n), ok(true){}
}e[maxn << 1];
int fir[maxn] = {0}, cnt = 1;
inline void ins(int u, int v){
    e[++cnt] = Edge(v, fir[u]); fir[u] = cnt;
    e[++cnt] = Edge(u, fir[v]); fir[v] = cnt;
}
int val[maxn], vis[maxn] = {0};
int rt1, rt2;
long long f[maxn][2];
void dp(int u, int T){
    vis[u] = T;
    f[u][0] = 0;
    f[u][1] = val[u];
    for(int v, i = fir[u]; i; i = e[i].next){
        v = e[i].to;
        if(!e[i].ok || vis[v] == T) continue;
        dp(v, T);
        f[u][0] += max(f[v][0], f[v][1]);
        f[u][1] += f[v][0];
    }
}
void dfs(int u, int f){
    vis[u] = 1;
    for(int v, i = fir[u]; i; i = e[i].next){
        v = e[i].to;
        if(i ^ f){
            if(vis[v]){
                rt1 = u;
                rt2 = v;
                e[i].ok = false;
                e[i ^ 1].ok = false;
            }
            else dfs(v, i ^ 1);
        }
    }
}
int main(){
    int n = readint();
    for(int i = 1; i <= n; i++){
        val[i] = readint();
        ins(i, readint());
    }
    long long ans = 0, t;
    for(int i = 1; i <= n; i++)
        if(!vis[i]){
            rt1 = rt2 = 0;
            dfs(i, 0);
            if(!rt1){
                dp(i, 2);
                ans += max(f[i][0], f[i][1]);
            }
            else{
                dp(rt1, 2);
                t = f[rt1][0];
                dp(rt2, 3);
                t = max(t, f[rt2][0]);
                ans += t;
            }
        }
    printf("%lld\n", ans);
    return 0;
}

 

以上是关于[ZJOI2008]骑士的主要内容,如果未能解决你的问题,请参考以下文章

[ZJOI2008]骑士

BZOJ 1040: [ZJOI2008]骑士

bzoj1040[ZJOI2008]骑士

BZOJ1040: [ZJOI2008]骑士

ZJOI2008骑士[树形dp]

bzoj 1040 1040: [ZJOI2008]骑士