您的位置:首页 > 其它

2013 多校第二场 hdu 4616 Game

2013-07-26 16:33 239 查看
hdu 4616

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

题目大意:给你一棵有n个节点的树,编号0~n-1,你先开始可以进入到任意一个节点,每个点都有一定的val,并可能有陷阱,你最多只能碰到 c 个陷阱,到碰到 c 个陷阱时,你马上就 Game Over 了,不能再继续走了,不管后面还有没有陷阱。问你最大能获得的 val 值。

思路:一看就知道肯定是树形DP,可是这道题目中刚碰到 c 马上就死了,这样就和一般的不超过 c 个求最大的长度的题目有所不同,这也是最令人头疼的地方,感觉好难处理。所以还得再开一维,来表示方向,0表示从这个节点出去,1表示回来 (这一维也是看了别人的博客,他这么写的,才顿有所感的)。d[ u ][ i ][ 0 ] 表示以u为根节点的子树,碰到 i 个陷阱,而且方向是出去的最大val值,d[ u ][ i ][ 1 ] 同理,表示回来的。如果用v来表示当前处理的子节点,ans取值的时候,不仅是d[ u
][ i ][ 0 ] + d[ v ][ j ][ 1 ](i + j <= c, i  != c)和 d[ u ][ i ][ 1 ] + d[ v ][ j ][ 0 ] (i + j <= c,j  != c)  ,还有一个是 d[ u ][ i ][ 1 ] + d[ v ][ j ][ 1 ] (i + j < c),而两个0可以不用。状态转移方程很简单,d[ u ][ i ][ 0 ]  = max(d[ v ][ i ][ 0 ] + val), d[ u ][ i ][ 1 ]  = max(d[
v ][ i ][ 1 ] + val),这里还要注意,如果用cc表示当前节点的陷阱值,0表示出去,所以 i == cc 时,d[ u ][ cc ][ 0 ] 一定为当前节点的val,所以上述状态方程 0 的时候 i 的范围为 cc ~ c,1 的时候为 cc + 1 ~ c 。

另外,因为 c 比较小,最大才为3,经过亲测,这道题对每个点都暴力一遍,找最大值,这样也能过。。 = =

代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int INF = 0x0fffffff ;

const int MAXN = 55555 ;

struct Edge
{
int t,next;
} edge[MAXN<<1];

int tot,head[MAXN];

void add_edge(int s,int t)
{
edge[tot].t=t;
edge[tot].next = head[s];
head[s] = tot++;
}

struct Node
{
int val,c;
} node[MAXN];

int n,c;

int d[MAXN][5][2];//0表示出去,1表示进来

int ans;

void dfs(int u,int fa)
{
int cc = node[u].c;
int vv = node[u].val;
for(int i = 0;i<=c;i++)
d[u][i][0] = d[u][i][1] = - INF;
d[u][cc][0] = d[u][cc][1] = vv;
for(int e = head[u];e!=-1;e= edge[e].next)
{
int v =edge[e].t;
if(v==fa) continue;
dfs(v,u);
for(int i = cc;i<=c;i++)
{
for(int j = 0;j<=c;j++)
{
if(i+j>c) break;;
if(i!=c) ans = max(ans , d[u][i][1]+d[v][j][0]);
if(j!=c) ans = max(ans , d[u][i][0]+d[v][j][1]);
if(i+j<c)
{
//ans = max(ans,d[u][i][0]+d[v][j][0]);
ans = max(ans,d[u][i][1]+d[v][j][1]);
}
}
}
for(int i = cc;i<=c;i++)
{
if(i==cc) d[u][i][0] = vv;
else d[u][i][0] = max(d[u][i][0],d[v][i-cc][0]+vv);
}

for(int i = cc;i<=c;i++)
{
d[u][i][1] = max(d[u][i][1],d[v][i-cc][1]+vv);
}
}
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&c);
for(int i=0;i<n;i++)
{
scanf("%d%d",&node[i].val,&node[i].c);
}
tot=0;
memset(head,-1,sizeof(head));
int a,b;
for(int i =1;i<n;i++)
{
scanf("%d%d",&a,&b);
add_edge(a,b);
add_edge(b,a);
}
ans=0;
dfs(0,-1);
printf("%d\n",ans);
}
return 0;
}
/*
7 3
55 1
12 1
66 0
44 1
42 0
23 0
56 1
0 1
0 2
1 3
1 4
3 5
3 6
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: