_what

博客园 首页 新随笔 联系 订阅 管理

今天准备学树形DP,于是查看了POJ题目分类,打开了POJ2057,发现对于我来说太难了,做不了,于是找了一些入门题来学。

poj2342 父子节点不同时选
题意:
一个树,每个点有一个“快乐”值,父子结点不能同时快乐,问这个结构的最大快乐值

用act[i][0]表示编号为i的人不参加聚会,act[i][1]表示编号为i的人参加聚会。
经过简单思考,可以得出状态转移方程: act[i][1] += act[son][0];
act[i][0] += max(act[son][0], act[son][1]);
因为要先计算叶子节点, 所以从根节点开始DFS。
代码如下:

typedef long long LL;
typedef unsigned long long ULL;
using namespace std;

// bool Sqrt(LL n) { return (LL)sqrt(n) * sqrt(n) == n; }
const double PI = acos(-1.0), ESP = 1e-10;
const LL INF = 99999999999999;
const int inf = 999999999, N = 6000 + 24;
LL act[N][2];
int cnt, head[N], n;
struct Edge {
	int to, _next;
}e[N];

void addEdge(int from, int to) {
	e[cnt].to = to;
	e[cnt]._next = head[from];
	head[from] = cnt++;
}

void dfs(int cur) {
	for(int i = head[cur]; i != -1; i = e[i]._next) {
		int to = e[i].to;
		dfs(to);
		act[cur][0] += max(act[to][1], act[to][0]);
		act[cur][1] += act[to][0];
	}
}

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	scanf("%d", &n);
	memset(act, 0, sizeof act);
	for(int i = 1; i <= n; i++) scanf("%lld", &act[i][1]);    //根据题意,读入i号参加聚会的快乐值
	int a, b; cnt = 0;
	memset(head, -1, sizeof head);
	LL start = n * (n + 1) / 2;
	while(scanf("%d%d", &a, &b) == 2 && (a || b)) {
		addEdge(b, a);
		start -= (LL)a;
	}
	dfs((int)start);            //start是根节点的编号
	printf("%lld\n", max(act[start][1], act[start][0]));

	return 0;
}
posted on 2019-10-09 17:40  _what  阅读(188)  评论(0编辑  收藏  举报