NOIP模拟(20171026)T3 大逃杀

一棵带权树,第一次经过一个节点需ti时间,获得wi的武力值
求T时间内获得的最大武力值
n,T300
树形dp神题(告诉了我什么叫转移顺序)
dp[i][j][0/1/2] 表示路径的 【起点终点都在i/起点(或终点)在i,另一点在i的子树内(因为路径是可逆的)/起点终点都在i的子树】 内能得到的最大武力值
转移即可(说的容易!!!)
dp[i][j][2]dp[i][jdis(i,v)2k][2]+dp[v][k][0](vson[i])
dp[i][j][2]dp[i][jdis(i,v)2k][0]+dp[v][k][2](vson[i])
dp[i][j][2]dp[i][jdis(i,v)k][1]+dp[v][k][1](vson[i])
dp[i][j][1]dp[i][jdis(i,v)2k][1]+dp[v][k][0](vson[i])
dp[i][j][1]dp[i][jdis(i,v)k][0]+dp[v][k][1](vson[i])
dp[i][j][0]dp[i][jdis(i,v)2k][0]+dp[v][k][0](vson[i])
注意,转移时一定一定一定要用上一个子树的状态来更新这个子树的状态(类似背包的降维优化)
注意,树边权可为0(个中含义自行体会)

#include<bits/stdc++.h>
#define LEN 350
/*中间一对地方不能反,反了的话,呵呵*/
using namespace std;
inline int getint(){
    int x=0,p=1;
    char c=getchar();
    while(!isdigit(c)){
        if(c=='-')p=-1;
        c=getchar();
    }
    while(isdigit(c)){
        x=(x<<3)+(x<<1)+(c^'0');
        c=getchar();
    }
    return x*p;
}
inline void putint(long long x){
    if(x<0){
        x=-x;
        putchar('-');
    }
    static int buf[30];
    int tot=0;
    do{
        buf[tot++]=x%10;
        x/=10;
    }while(x);
    while(tot)putchar(buf[--tot]+'0');
}
int n,T;
struct road{
    int e,nxt,len;
}r[LEN*2];
struct node{
    int first,fa,w,t;
    int dp[LEN][5];
}t[LEN];
int tot=1;
inline void creat(int a,int b,int c){
    r[++tot].e=b;
    r[tot].len=c;
    r[tot].nxt=t[a].first;
    t[a].first=tot;
}
int ans=0;
void dfs(int cur){
    for(int i=0;i<=300;++i){
        for(int j=0;j<5;++j){
            t[cur].dp[i][j]=-0xfffffff;
        }
    }
    for(int i=t[cur].t;i<=300;++i){
        t[cur].dp[i][0]=t[cur].dp[i][1]=t[cur].dp[i][2]=t[cur].w;
    }
    for(int i=t[cur].first;i;i=r[i].nxt){
        int v=r[i].e;
        if(v==t[cur].fa)continue;
        t[v].fa=cur;
        dfs(v);
        for(int j=T;j>=0;--j){                     //不能反
            for(int k=0;k<=T;++k){                 //不能反*2
                if(j-r[i].len*2-k>=t[cur].t) t[cur].dp[j][2]=
                max(t[cur].dp[j][2], t[cur].dp[j-r[i].len*2-k][2]+t[v].dp[k][0]);
                if(j-r[i].len*2-k>=t[cur].t) t[cur].dp[j][2]=
                max(t[cur].dp[j][2],t[cur].dp[j-r[i].len*2-k][0]+t[v].dp[k][2]);
                if(j-r[i].len-k>=t[cur].t) t[cur].dp[j][2]=
                max(t[cur].dp[j][2],t[cur].dp[j-r[i].len-k][1]+t[v].dp[k][1]);
                if(j-r[i].len*2-k>=t[cur].t) t[cur].dp[j][1]=
                max(t[cur].dp[j][1],t[cur].dp[j-r[i].len*2-k][1]+t[v].dp[k][0]);
                if(j-r[i].len-k>=t[cur].t) t[cur].dp[j][1]=
                max(t[cur].dp[j][1],t[cur].dp[j-r[i].len-k][0]+t[v].dp[k][1]);
                if(j-r[i].len*2-k>=t[cur].t) t[cur].dp[j][0]=
                max(t[cur].dp[j][0],t[cur].dp[j-r[i].len*2-k][0]+t[v].dp[k][0]);
                //不能反*3
            }
        }
    }
    //cout<<cur<<endl;
    for(int j=T;j>=0;--j){
        //cout<<j<<" "<<t[cur].dp[j][0]<<" "<<t[cur].dp[j][1]<<" "<<t[cur].dp[j][2]<<endl;
        ans=max(ans,max(t[cur].dp[j][0],(t[cur].dp[j][1],t[cur].dp[j][2])));
    }
}
int main(){
    n=getint(),T=getint();
    bool f=1;
    for(int i=1;i<=n;++i){
        t[i].w=getint();
        if(t[i].w)f=0;
    }
    if(f){
        cout<<0;
        return 0;
    }
    for(int i=1;i<=n;++i){
        t[i].t=getint();
    }
    for(int i=1;i<n;++i){
        int a=getint(),b=getint(),c=getint();
        creat(a,b,c),creat(b,a,c);
    }
    dfs(1);
    cout<<ans<<endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值