题目链接:

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

题目大意:

给一棵树,每个节点有一个礼物值及是否有trick,每来到一个节点必须拿礼物,如果该节点有trick则浪费一个抗trick机会,如果一开始有C次抗trick的机会,问最多可以拿多少值的礼物,机会用完后就结束了。访问了的节点不能再次访问。

解题思路:

树形dp啊。

树形dp很不熟悉阿阿阿阿阿阿阿阿。。。。

dp[i][j][0]表示从节点i开始,有j次机会,在子树中最大的能拿到礼物的值。

dp[i][j][1]表示从节点i开始,有j次机会,在子树中次大的能拿到礼物的值。

by[i][j]表示i节点,有j次机会时,得到最大值的那个直接儿子标号。

先以任意一点为根,dfs一遍。求出从每个节点的开始的在子树中的最大值和次大值。

再以同一点为根,dfs一遍,参数维护一个以父亲为开始节点且不经过该节点的最大值。求出该节点出发的在整棵树中的最大值。

PS:

注意此题麻烦的地方是,当机会恰好用完时,游戏结束,不能累加后面的0机会值。

所以要分该节点是否有trick来判断,如果有trick的话,只有j>=2时有从后面更新。

PS2:要多做树形dp啊。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; //freopen("data.in","r",stdin);
//freopen("data.out","w",stdout); #define Maxn 55000
ll dp[Maxn][5][2]; //dp[i][j][0]表示从i节点开始有j个机会,在子树中能达到的最大值
int tra[Maxn],val[Maxn],cnt,n,c;
int by[Maxn][5];
ll ans; struct Edge //邻接表
{
int v;
struct Edge * next;
}edge[Maxn<<1],*head[Maxn<<1]; void add(int a,int b)
{
++cnt;
edge[cnt].v=b,edge[cnt].next=head[a];
head[a]=&edge[cnt];
}
ll Max(ll a,ll b)
{
return a>b?a:b;
}
void dfs1(int pre,int cur)
{
struct Edge * p=head[cur];
bool flag=true;
while(p)
{
if(p->v!=pre)
{
flag=false;
dfs1(cur,p->v); //先计算出子树情况
if(tra[cur]) //该节点有trick
{
dp[cur][1][0]=val[cur];
for(int i=2;i<=c;i++) //必须大于等于2的情况才可能从后面更新
{
if(dp[p->v][i-1][0]+val[cur]>=dp[cur][i][0])
{
dp[cur][i][1]=dp[cur][i][0];//更新次大
dp[cur][i][0]=dp[p->v][i-1][0]+val[cur];
by[cur][i]=p->v;
}
else if(dp[p->v][i-1][0]+val[cur]>dp[cur][i][1])
{ //更新次大
dp[cur][i][1]=dp[p->v][i-1][0]+val[cur];
}
}
}
else
{ //如果没有trick,则可以到达其他点任何点
for(int i=0;i<=c;i++)
{
if(dp[p->v][i][0]+val[cur]>=dp[cur][i][0])
{
dp[cur][i][1]=dp[cur][i][0];
dp[cur][i][0]=dp[p->v][i][0]+val[cur];
by[cur][i]=p->v;
}
else if(dp[p->v][i][0]+val[cur]>dp[cur][i][1])
{
dp[cur][i][1]=dp[p->v][i][0]+val[cur];
}
}
}
}
p=p->next;
}
if(flag) //叶子节点单独处理
{
for(int i=tra[cur];i<=c;i++)
dp[cur][i][0]=val[cur];
}
}
void dfs2(int pre,int cur,ll *aa)
{
ll MM=0;
if(tra[cur])
{
MM=dp[cur][c][0];//从子树中找
if(c>=2)
MM=Max(MM,aa[c-1]+val[cur]); //从父亲找
}
else
MM=Max(dp[cur][c][0],aa[c]+val[cur]);
if(MM>ans)
ans=MM;
/* printf("cur:%d ans:%I64d \n",cur,MM);
for(int i=0;i<=c;i++)
printf("aa[%d]:%I64d ",i,aa[i]);
putchar('\n');
system("pause");*/
struct Edge * p=head[cur];
while(p)
{
if(p->v!=pre)
{
ll tt[5]={0}; //tt[i]表示父亲有i次机会且不通过该儿子时能达到的最大值
if(tra[cur])
{
tt[1]=dp[cur][1][0]; //注意更新
for(int i=2;i<=c;i++)
{
if(p->v!=by[cur][i]) //最大值是该儿子,用次大的来更新
tt[i]=Max(aa[i-1]+val[cur],dp[cur][i][0]);
else
tt[i]=Max(aa[i-1]+val[cur],dp[cur][i][1]);
}
}
else
{
for(int i=0;i<=c;i++)
{
if(p->v!=by[cur][i])
tt[i]=max(aa[i]+val[cur],dp[cur][i][0]);
else
tt[i]=max(aa[i]+val[cur],dp[cur][i][1]);
}
}
/* for(int i=0;i<=c;i++)
printf("i:%d %d\n",i,tt[i]);*/
dfs2(cur,p->v,tt);
}
p=p->next;
} } int main()
{
int t,a,b; //freopen("1006.in","r",stdin);
//freopen("1006ans.out","w",stdout);
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&c);
memset(by,-1,sizeof(by));
memset(head,NULL,sizeof(head));
for(int i=0;i<n;i++)
scanf("%d%d",&val[i],&tra[i]);
cnt=0;
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
memset(dp,0,sizeof(dp));
ans=0;
dfs1(-1,0);
ll tt[5]={0};
dfs2(-1,0,tt);
printf("%I64d\n",ans);
}
return 0;
}

树形dp hdu-4616-Game的更多相关文章

  1. fwt优化+树形DP HDU 5909

    //fwt优化+树形DP HDU 5909 //见官方题解 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ #include <bits/ ...

  2. HDU - 1054 Strategic Game(二分图最小点覆盖/树形dp)

    d.一颗树,选最少的点覆盖所有边 s. 1.可以转成二分图的最小点覆盖来做.不过转换后要把匹配数除以2,这个待细看. 2.也可以用树形dp c.匈牙利算法(邻接表,用vector实现): /* 用ST ...

  3. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  4. HDU 4616 Game (搜索)、(树形dp)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4616 这道题目数据可能比较弱,搜索都可以AC,但是不敢写,哎…… 搜索AC代码: #include & ...

  5. HDU 1520 树形dp裸题

    1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> ...

  6. HDU 1561 树形DP入门

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  7. POJ 2342 &&HDU 1520 Anniversary party 树形DP 水题

    一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点) ...

  8. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  9. hdu 4003 Find Metal Mineral 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...

  10. 树形DP+树状数组 HDU 5877 Weak Pair

    //树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...

随机推荐

  1. 学点编码知识又不会死:Unicode的流言终结者和编码大揭秘

    如果你是一个生活在2003年的程序员,却不了解字符.字符集.编码和Unicode这些基础知识.那你可要小心了,要是被我抓到你,我会让你在潜水艇里剥六个月洋葱来惩罚你. 这个邪恶的恐吓是Joel Spo ...

  2. Linux下C语言多文件的编译以及makefile的应用

    1.关于编译和链接 一般来说,无论是C.C++,首先要把源文件编译成中间代码文件,在Windows下也就是.obj文件,UNIX下是.o文件,即Object File,这个动作叫做编译(compile ...

  3. 20162325 金立清 S2 W6 C15

    20162325 2017-2018-2 <程序设计与数据结构>第6周学习总结 教材学习内容概要 队列是先进先出(FIFO)的集合 队列是保存重复编码k值的一种有效结构 实现模拟时常用队列 ...

  4. div块元素垂直水平居中方法总结

    1.已知块级元素的宽和高,使用绝对定位+外边距设定水平垂直居中. 父元素position:relative,子元素position:absolute;top:50%;left:50%;margin-t ...

  5. [NC13C]形态形成场/[Gym100430B]Divisible Substrings

    [NC13C]形态形成场/[Gym100430B]Divisible Substrings 题目大意: 有\(m(m\le26)\)个字符串替换式\(S_i(|S_i\le100|)\),表示某个大写 ...

  6. [YC703]ゴミ拾い Easy

    [YC703]ゴミ拾い Easy 题目大意: 二维平面内有\(n(n\le3\times10^5)\)个人和\(n\)个物品,第\(i\)个人在\((a_i,0)\)上,第\(i\)个物品在\((x_ ...

  7. Codeforces Beta Round #8 C. Looking for Order 状压

    C. Looking for Order 题目连接: http://www.codeforces.com/contest/8/problem/C Description Girl Lena likes ...

  8. linux命令: Netstat

    在Internet RFC标准中,Netstat的定义是: Netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告.    Netstat是控 ...

  9. TortoiseSVN 修改密码

    在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果 ...

  10. HDU 4498 Function Curve (分段,算曲线积分)

    Function Curve Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)To ...