树形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 ;
}