树形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/archive/2010/12/02/1894101.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值