树形DP,是一个很好理解的DP,树形结构很容易理解DP的!
在存储结构上,学习了左孩子,右兄弟的结构:
定义代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*简单树形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表示最优子结点的距离
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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;
}