5819. 【NOIP提高A组模拟2018.8.15】 大逃杀

Description

自从 Y 君退役之后,她就迷上了吃鸡,于是她决定出一道吃鸡的题。
Y 君将地图上的所有地点标号为 1 到 n,地图中有 n − 1 条双向道路连接这些点,通过一条 双向道路需要一定时间,保证从任意一个点可以通过道路到达地图上的所有点。
有些点上可能有资源,Y 君到达一个有资源的点后,可以选择获取资源来使自己的武力值增 加 wi,也可以选择不获取资源。如果 Y 君获取了一个点上的资源,这个点上的资源就会消失,获 取资源不需要时间。
有些点上可能有敌人,Y 君到达一个有敌人的点后,必须花费 ti 秒伏地与敌人周旋,并最终 将敌人消灭。如果 Y 君消灭了一个点上的敌人,这个点上的敌人就会消失。Y 君不能无视敌人继 续前进,因为这样会被敌人攻击。
如果一个点上既有资源又有敌人,Y 君必须先消灭敌人之后才能获取资源,否则就会被敌人 突袭。
游戏开始时,Y 君可以空降到任意一个点上,接下来,她有 T 秒进行行动,T 秒后她就必须 前往中心区域送快递。Y 君希望她前往中心区域送快递时,武力值尽可能大,请你帮助 Y 君设计 路线,以满足她的要求。你只需输出 T 秒后 Y 君的武力值。

Input

第一行由单个空格隔开的两个正整数 n, T,代表点数和时间。
第二行 n 个由单个空格隔开的非负整数代表 wi,如果 wi = 0 代表该点没有武器,
第三行 n 个由单个空格隔开的非负整数代表 ti,如果 ti = 0 代表该点没有敌人。
接下来 n − 1 行每行由单个空格隔开的 3 个非负整数 a, b, c 代表连接 a 和 b 的双向道路,通 过这条道路需要 c 秒。

Output

输出一行一个整数代表 T 秒后 Y 君的武力值。

Sample Input

17 54
5 5 1 1 1 25 1 10 15 3 6 6 66 4 4 4 4
0 1 3 0 0 0 1 3 2 0 6 7 54 0 0 0 0
1 8 3
2 8 3
8 7 7
7 13 0
7 14 0
15 14 2
16 14 3
17 14 5
7 9 4
9 10 25
10 11 0
10 12 0
7 6 20
3 6 3
3 4 3
3 5 3

Sample Output

68

Data Constraint

这里写图片描述

题解:

10%输出0
20%不会。
40%可以直接做一遍背包。
60%不知道。
还是直接上100%把。

首先,我们这题显然是一道树形DP题。
我们可以设三个状态转移方程——
f[i,j]进入以i为根的子树并返回到i
g[i,j]进入以i为根的子树但不返回到i
h[i,j]从以i为根的子树里一点出发,经过i点并调回以i为根的子树中
用了j秒的最大武力值。

这是一张通用的图。
这里写图片描述
于是乎,我们可以对于每一个方程来讨论。
对于f[i,j]:f[i,j]:=max(f[i,j],f[i,j-k-2val]+f[son,k]);
表达的意思是:先从i(红色)走到儿子节点,有k的时间在i的儿子节点走,走到后返回son,然后返回i,然后i再走j-k-2
val的时间返回到i。
这里写图片描述

对于g[i,j]:
g[i,j]:=max(g[i,j],g[son,k]+f[i,j-k-val]);
表达的意思是:在i这个节点先乱走一通,回到i点,然后再走到son的节点,给这个节点k的时间走,走完之后不回来了。
这里写图片描述
g[v,j]:=max(g[i,j],g[i,j-k-2*val]+f[son,k]);
表达的意思是:在i这个节点上,走到一个儿子,然后乱走回到这个儿子,返回i点,最后再走完后不回来了。
这里写图片描述

对于h[i,j]
h[i,j]:=max(h[i,j],g[i,j-k-val]+g[son,k]);
表达的意思是:首先,从i乱走,然后,i的儿子乱走,两段连起来就相当于从i子树中一个点走到i,走到i的一个儿子,再走到终点。
这里写图片描述
h[i,j]:=max(h[i,j],f[i,k]+h[son,j-k-2*val]);
表达的意思是:首先,i的儿子的h找到,再从i乱走一通,回到i点。拆开来看就相当于son的子树中一点走到son再走到i再乱走返回i再回到son再乱走。

这里写图片描述
相当于:
这里写图片描述
h[i,j]:=max(h[i,j],f[son,k]+h[i,j-k-2*val]);
表达的意思是:首先,i的h找到,再从son乱走一通,回到son点。拆开来看就相当于i的子树中一点走到i再走到son再乱走返回son再回到i再乱走。
这里写图片描述
相当于:
这里写图片描述

然后,就可以很舒服地DP啦。
只是要注意一些DP顺序,否则会导致算重,还有就是边界条件(卡了我好久)

标程

uses math;
var
        i,j,k,l,n,m,time,tot,ans:longint;
        x,y,z,tov,next,last,val:array[1..10000] of longint;
        f,g,h:array[1..300,0..300] of longint;
        w,t:array[1..300] of longint;

procedure insert(x,y,z:longint);
begin
        inc(tot);
        tov[tot]:=y;
        next[tot]:=last[x];
        last[x]:=tot;
        val[tot]:=z;
end;

procedure dfsf(v,fa:longint);
var
        i,j,k:longint;
        yz:boolean;
begin
        if t[v]>time then exit;
        i:=last[v];
        yz:=false;
        while i>0 do
        begin
                if tov[i]<>fa then
                begin
                        yz:=true;
                        dfsf(tov[i],v);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=2*val[i] then
                                                h[v,j]:=max(h[v,j],f[tov[i],k]+h[v,j-k-2*val[i]]);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=2*val[i] then
                                                h[v,j]:=max(h[v,j],f[v,k]+h[tov[i],j-k-2*val[i]]);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=val[i] then
                                                h[v,j]:=max(h[v,j],g[v,j-k-val[i]]+g[tov[i],k]);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=2*val[i] then
                                                g[v,j]:=max(g[v,j],g[v,j-k-2*val[i]]+f[tov[i],k]);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=val[i] then
                                                g[v,j]:=max(g[v,j],g[tov[i],k]+f[v,j-k-val[i]]);
                        for j:=time downto 0 do
                                for k:=0 to j do
                                        if j-k>=2*val[i] then
                                                f[v,j]:=max(f[v,j],f[v,j-k-2*val[i]]+f[tov[i],k]);
                end;
                i:=next[i];
        end;
        //        f[v,t[v]]:=w[v];
        begin
                for i:=time downto t[v] do
                begin
                        f[v,i]:=f[v,i-t[v]]+w[v];
                        g[v,i]:=g[v,i-t[v]]+w[v];
                        h[v,i]:=h[v,i-t[v]]+w[v];
                end;
                for i:=min(t[v]-1,time) downto 0 do
                begin
                        f[v,i]:=0;
                        g[v,i]:=0;
                        h[v,i]:=0;
                end;
        end;
end;
begin
        assign(input,'toyuq.in');reset(input);
        assign(output,'toyuq.out');rewrite(output);
        readln(n,time);
        for i:=1 to n do
        begin
                read(w[i]);
                ans:=max(w[i],ans);
        end;
        if ans=0 then
        begin
                writeln(0);
                halt;
        end;
        readln;
        for i:=1 to n do read(t[i]);
        for i:=1 to n-1 do
        begin
                readln(x[i],y[i],z[i]);
                insert(x[i],y[i],z[i]);
                insert(y[i],x[i],z[i]);
        end;
        dfsf(1,0);
        ans:=0;
        for i:=1 to n do
        begin
                ans:=max(ans,h[i,time]);
        end;
        writeln(ans);
end.

转载于:https://www.cnblogs.com/RainbowCrown/p/11148396.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值