【问题描述】
有个公司要举行一场晚会。为了能玩得开心,公司领导决定:如果邀请了某个人,那么一定不会邀请他的上司(上司的上司,上司的上司的上司……都可以邀请)。每个参加晚会的人都能为晚会增添一些气氛,求一个邀请方案,使气氛值的和最大。所有员工的编号为1~N。
【输入格式】
第1行一个整数N(1<=N<=6000)表示公司的人数。
接下来N行每行一个整数。第i行的数表示第i个人的气氛值x(-128<=x<=127)。
接下来每行两个整数L,K。表示K是 L的上司。
输入以0 0结束。
【输出格式】
一个数,最大的气氛值和。
【输入样例】
7
1 1 1 1 1 1 1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
【输出样例】5
【解析】
这道题..
不知道说什么.. 一开始出于习惯瞬间把森林转二叉树打完了..
结果发现根本不用..
只需要用f[i][0]和f[i][1]来存状态..
f[i][0]表示不请i的最大收益
f[i][1]表示请i的最大收益
知道这两个状态就ok了..
然后就TreeDP吧
void Tree_DP ( int x ){
if ( f[x][0] != -1 || f[x][1] != -1 ) return;
if ( x < 0 ) return;
int i, j, k, f1, f0;
f0 = 0; f1 = w[x];
for ( k = first[x]; k; k = a[k].next ){
Tree_DP (a[k].y);
f1 += f[a[k].y][0];
f0 += _max ( f[a[k].y][0], f[a[k].y][1] );
}
f[x][0] = f0; f[x][1] = f1;
}
大概就是这样了..
【代码】
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
int w[6100], n;
struct edgenode {
int x, y, next;
}a[6100]; int first[6100], len;
void ins ( int x, int y ){
len ++;
a[len].x = x; a[len].y = y;
a[len].next = first[x]; first[x] = len;
}
int f[6100][2];
bool v[6100];
int _max ( int x, int y ){ return x > y ? x : y; }
void Tree_DP ( int x ){
if ( f[x][0] != -1 || f[x][1] != -1 ) return;
if ( x < 0 ) return;
int i, j, k, f1, f0;
f0 = 0; f1 = w[x];
for ( k = first[x]; k; k = a[k].next ){
Tree_DP (a[k].y);
f1 += f[a[k].y][0];
f0 += _max ( f[a[k].y][0], f[a[k].y][1] );
}
f[x][0] = f0; f[x][1] = f1;
}
int main (){
int i, j, k, x, y;
scanf ( "%d", &n );
for ( i = 1; i <= n; i ++ ) scanf ( "%d", &w[i] );
memset ( v, false, sizeof (v) );
while ( scanf ( "%d%d", &x, &y ) && x != 0 || y != 0 ){
ins ( y, x ); v[x] = true;
}
for ( i = 1; i <= n; i ++ ){
if ( v[i] == false ){
ins ( 0, i );
}
}
memset ( f, -1, sizeof (f) );
Tree_DP (0);
printf ( "%d\n", f[0][0] );
return 0;
}