HDU1520 Anniversary party
题面:
给一颗树,每个结点都有各自的价值,选择一些不相邻的结点使得收益最大。
解题过程:
- 树上相邻的结点不能同时选上,用 f [ x ][ 2 ] 第二维的 0 和 1 来表示不选和选这个节点所能达到的最大收益。
状态转移方程为:
f[x][0] += max( (ll)0, max(f[y][0], f[y][1]));
f[x][1] += max( f[y][0], (ll)0);关于数据。之前交了POJ2342,用的是错误的转移方程(先把子节点全选的收益res_0 和 全不选的收益 res_0 计算出来,再进行转移),居然AC了。说明这个题POJ的数据比HDU要水很多。
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
#define rep(i,l,p) for(int i=l;i<=p;i++)
#define fread() freopen("in.txt","r",stdin)
typedef long long ll;
typedef pair<int,int> P;
#define Fi first
#define Se second
#define mp make_pair
int n;
int v[6005];
int head[6005],tot;
struct Edge
{
int v,nx;
}edge[6600];
void add(int u,int v){
edge[++tot].nx = head[u]; head[u] = tot;
edge[tot].v = v;
}
int dig[66000];
ll f[6600][2];
void solve(int x){
f[x][1] = v[x];
if(head[x] == -1) return;
ll res_0 = 0,res_1 = 0;
for(int i=head[x];i!=-1;i=edge[i].nx){
int y = edge[i].v;
solve(y);
f[x][0] += max((ll)0,max(f[y][0],f[y][1]));
f[x][1] += max(f[y][0],(ll)0);
}
// f[x][0] = max(f[x][0],res_1);
}
int main(int argc, char const *argv[])
{
//fread();
ios::sync_with_stdio(false);
while(cin >> n){
memset(head,-1,sizeof head); tot =0;
rep(i,1,n) cin >> v[i];
memset(dig,0,sizeof dig);
memset(f,0,sizeof f);
int u,to;
while(cin >> to >> u && u && to){
add(u,to);
dig[to]++;
}
int root;
rep(i,1,n){
if(dig[i] == 0) {
root = i;
break;
}
}
solve(root);
ll ans = max(f[root][0],f[root][1]);
// rep(i,1,n) cout << f[i][0] << " " << f[i][1] << endl;
cout << ans << endl;
}
return 0;
}