LOI 2607 [ZJOI2008]骑士

题目描述

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

输入输出

输入格式:
输入文件knight.in第一行包含一个正整数N,描述骑士团的人数。
接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。
输出格式:
输出文件knight.out应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

数据范围

对于30%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 100;
对于80%的测试数据,满足N ≤ 10 000。
对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。

分析

虽然题目中所给的条件是环,但是可以破环转换成没有上司的舞会的一类的树形dp问题,还是比较简单的,主要注意破环后的两个点不能同时去的情况。

#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
    char ch = getchar();
    int x = 0 , f = 1 ;
    while( !isdigit( ch ) )
           if( ch == '-' ) f = -1 , ch = getchar();
           else ch = getchar();
    while( isdigit( ch ) )
           x = (ch  - '0') + (x << 3) + (x << 1) , ch =  getchar();
    return x * f;
}
const int maxn = 1000000 + 5;
int head[maxn] , atk[maxn] , _t = 0;
struct edge{
    int v , nxt;
} e[maxn * 2];
inline void addedge( int u , int v ){
    e[_t].v = v , e[_t].nxt = head[u] , head[u] = _t++;
}
typedef long long ll;
const ll INF = 0x7f7f7f7f7f7f;
ll f[maxn][2];
bool vis[maxn] , flg = 0;
int cir1 , cir2;
void dfs( int u , int fa ){ // Find circle
    vis[u] = 1;
    erep( i , u ){
        int v = e[i].v;
        if( v == fa ) continue;
        if( !vis[v] ) dfs( v , u );
        else if( vis[v] && !flg ){ flg = 1; cir1 = u , cir2 = v; e[i].v = e[i ^ 1].v = 0; } 
    }
}
void DP( int u , int fa ){
    f[u][0] = 0;
    f[u][1] = atk[u];
    erep( i , u ){
        int v = e[i].v;
        if( !v || v == fa ) continue;
        DP( v , u );
        f[u][1] += f[v][0];
        f[u][0] += max( f[v][1] , f[v][0] );
    }
}
int main(){
    memset( head , 0xff , sizeof head );
    int N = _read() , t;
    rep( i , 1 , N ){
        atk[i] = _read() , t = _read();
        addedge( i , t ) ;  addedge( t , i );
    }
    ll ans = 0;
    rep( i , 1 , N ){
        if( vis[i] ) continue;
        flg = 0 , cir1 = cir2 = 0;
        dfs( i , -1 );
        if( !flg ){ DP( i , -1 ); ans += max( f[i][0] , f[i][1] ); }
        else{
            ll res = -INF;
            DP( cir1 , -1 );
            res = max( res , f[cir1][0] );
            DP( cir2 , -1 );
            res = max( res , f[cir2][0] );
            ans += res;
        }
    }   
    cout << ans << endl;
    return 0;
}
    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/qq_20449783/article/details/80914442
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞