树形DP 题目库

  树形DP,是一个很好理解的DP,树形结构很容易理解DP的!

  在存储结构上,学习了左孩子,右兄弟的结构:

定义代码:

定义代码
struct node{
int val;
int father;
int child;
int brother;
void init()
{
father
= child = brother = -1;
val
= 0;
}
}tree[maxn];

添加边:

void AddEdge(int a,int b,int c)
{
tree[b].father
= a;
tree[b].brother
= tree[a].child;
tree[a].child
= b;
tree[b].val
= c;//把边的值赋给了某点
}

hdu 1520   Anniversary party

http://acm.hdu.edu.cn/showproblem.php?pid=1520

简单树形DP,做的第一个DP。

代码
/*简单树形DP题,比较好的地方是用到了左孩子,右兄弟的森林存储结构*/

#include
<iostream>
using namespace std;
const long maxn = 6005;
#define max(a,b) (a>b?a:b)
int n;

struct node
{
int Take;
int Not;
int father;
int child;
int brother;
void init()
{
father
= child = brother = -1;
Take
= 0;
Not
= 0;
}
int Max()
{
return Take>Not?Take:Not;
}
}tree[maxn];

void Init()
{
int i,l,k;

for(i=1;i<=n;i++)
{
tree[i].init();

scanf(
"%d",&tree[i].Take);
}
while(scanf("%d%d",&l,&k)!=EOF && (l!=0 || k!=0))
{
tree[l].father
= k;
tree[l].brother
= tree[k].child;
tree[k].child
= l;
}

//把森林合成一棵树
int pre = -1;
for(i=1;i<=n;i++)
{
if(tree[i].father == -1)
{
tree[i].father
= 0;
tree[i].brother
= pre;
tree[
0].child = i;
pre
= i;
}
}
tree[
0].father = -1;
tree[
0].brother = -1;
tree[
0].Take = 0;
tree[
0].Not = 0;
}

void Sum(int dir)
{
int c = tree[dir].child;
while(c != -1)
{
Sum(c);
tree[dir].Take
+= tree[c].Not;
tree[dir].Not
+= tree[c].Max();
c
= tree[c].brother;
}
}

void print()
{
int num = tree[0].Max();
printf(
"%d\n",num);
}

int main()
{
while(scanf("%d",&n)!=EOF)
{
Init();
Sum(
0);
print();
}
return 0;
}

hdu 3660 Alice and Bob's Trip

http://acm.hdu.edu.cn/showproblem.php?pid=3660

Bob选最大子结点走,Alice选最小子结点走!

但因为要符合《L,R》,所以加一个判断条件:

tree[dir].sum + tree[c].ans + tree[c].val >= L && tree[dir].sum + tree[c].ans + tree[c].val <= R

 //c是dir点的一个子结点,sum表示从0结点到该点的距离,ans表示最优子结点的距离

代码
#include <iostream>
using namespace std;

const long inf = 1000000000;
const long maxn = 500005;
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
int n,L,R;

struct node
{
int child;
int father;
int brother;
int val;
  int sum;//从0结点到该点的值
int ans;//子结点到该点的最优值

void Init()
{
child
= father = brother = -1;
val
= 0;sum = 0;ans = 0;
}
}tree[maxn];

void Init()
{
int i;
int a,b,c;
for(i=0;i<n;i++)
tree[i].Init();

for(i=0;i<n-1;i++)
{
scanf(
"%d%d%d",&a,&b,&c);
tree[b].father
= a;
tree[b].brother
= tree[a].child;
tree[a].child
= b;
tree[b].val
= c;
}
}


void Sum(int dir)
{
int c = tree[dir].child;
while(c != -1)
{
tree[c].sum
= tree[tree[c].father].sum + tree[c].val;
Sum(c);
c
= tree[c].brother;
}
}

void Bfs(int dir,bool bol)
{
if(bol == 0)
tree[dir].ans
= 0;
else
tree[dir].ans
= inf;

int c = tree[dir].child;
if(c == -1)
tree[dir].ans
= 0;
while(c != -1)
{
Bfs(c,
!bol);
if(tree[dir].sum + tree[c].ans + tree[c].val >= L && tree[dir].sum + tree[c].ans + tree[c].val <= R)
{
if(bol == 0)
{
tree[dir].ans
= max(tree[dir].ans,tree[c].ans + tree[c].val);
}
else
{
tree[dir].ans
= min(tree[dir].ans,tree[c].ans + tree[c].val);
}
}

c
= tree[c].brother;
}
}

void Print()
{
if(tree[0].ans >= L && tree[0].ans <= R)
printf(
"%d\n",tree[0].ans);
else
printf(
"Oh, my god!\n");
}

int main()
{
while(scanf("%d%d%d",&n,&L,&R)!=EOF)
{
Init();
Sum(
0);
Bfs(
0,0);
Print();
}
return 0;
}
原文地址:https://www.cnblogs.com/silencExplode/p/1894101.html