题目描述
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;
}