[JSOI2008]魔兽地图

树上背包

题目传送门

首先,有没有哪位dalao 愿意告诉我为什么合成高级装备不需要附加金币,,

好吧,这个不重要

明确表示装备合成路线可以用一棵树来表示。一颗?傻乎乎的在下之前每次就只dp一棵树,不出意外的WA了,,在看几遍,好嘛,好像是个森林啊(泪奔)

最容易想到的dp[x][i][j]是第x件买了i个,花了j元的最高力量。但是,,这样好像就成为不可做题了(欢迎各路dalao打脸,反正不是我说的[手动滑稽](偷偷扔出FYJ挡枪)),那么换一种思路,还是dp[x][i][j],但表示的是第x件装备,用i件合成上级装备(即至少买了i件),花费j元的力量。如果i是基础装备,转移方程就直接出来了:d[x][i][j*cost[x]]=power[x]*(j-i)。

 如果是高级装备呢?

那就枚举它买多少件,以及它的子装备买多少件,直接暴力转移,n^2*times^2。看看时限,3s,完全不方

在下代码比较丑,求各位不要介意

#include<bits/stdc++.h>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iostream>
#define ll int
#define re register
#define inf 0x3f3f3f3f
#define inl inline
#define sqr(x) (x*x)
//#define eps 1e-8
#define debug printf("debug\n");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
using namespace std;
//const ll mod;
const ll MAXN=3e5+10;
inl ll read() {
    re ll x = 0; re int f = 1;
    char ch = getchar();
    while(ch<'0'||ch>'9') { if(ch== '-' ) f = -1; ch = getchar(); }
    while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x * f;
}
inl char readc() {
    char ch=getchar();
    while(('z'<ch||ch<'a')&&('Z'<ch||ch<'A')) ch=getchar();
    return ch;
}
inl void write(re ll x){
    if(x>=10)write(x/10);
    putchar(x%10+'0');
}
inl void writeln(re ll x){
    if(x<0) {x=-x;putchar('-');}
    write(x); puts("");
}
inl ll gcd(re ll x,re ll y){while(y^=x^=y^=x%=y);return x;}
inl void FR() {
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
}
inl void FC() {
    fclose(stdin);
    fclose(stdout);
}
struct Node {
    ll u,v,w,nxt;
}e[20005<<1];
ll cnt,head[60],ssw[60],g[20005],cost[60],times[60];
bool fl[60],in[60],vis[60];
ll ans[20005];
inl void adde(ll u,ll v,ll w) {
    e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
    e[cnt].nxt=head[u];head[u]=cnt;
}
ll d[60][105][2005],n,m;
void dp(ll x) {
    if(vis[x]) return ;vis[x]=1;
    if(!fl[x]) {//基础装备 
        times[x]=min(times[x],m/cost[x]);
        for(re ll i=times[x];~i;i--) {
            for(re ll j=i;j<=times[x];j++) {
                d[x][i][j*cost[x]]=ssw[x]*(j-i);
            }
        }
        return ;
    }
    for(re ll h=head[x];h;h=e[h].nxt) {
        dp(e[h].v);cost[x]+=e[h].w*cost[e[h].v];
        times[x]=min(times[x],times[e[h].v]/e[h].w);
    }
    times[x]=min(times[x],m/cost[x]);
    for(re ll i=times[x];~i;i--) {
        for(re ll j=1;j<=m;j++) g[j]=-inf;g[0]=0;
        for(re ll h=head[x];h;h=e[h].nxt) {
            for(re ll k=m;~k;k--) {
                re ll sst=-inf;
                for(re ll l=0;l<=k;l++) {sst=max(sst,g[k-l]+d[e[h].v][i*e[h].w][l]);}
                g[k]=sst;//花k元能到的最高力量 
            }
        }
        for(re ll j=0;j<=i;j++) {
            for(re ll l=0;l<=m;l++) {
                d[x][j][l]=max(d[x][j][l],g[l]+ssw[x]*(i-j));
            }
        }
    }
}
int main(){
//    FR();
    n=read(),m=read();
    memset(times,inf,sizeof(times));
    memset(d,-inf,sizeof(d));
    for(re ll i=1;i<=n;i++) {
        ssw[i]=read();
        char sj[3];scanf("%s",sj);
        if(sj[0]=='A') {
            fl[i]=1;re ll c=read();
            for(re ll j=1;j<=c;j++) {
                re ll sx=read(),xs=read();
                if(!in[sx]) in[sx]=1;
                adde(i,sx,xs);
            }
        }
        else if(sj[0]=='B') {
            fl[i]=0;cost[i]=read();
            times[i]=read();
        }
        else puts("RE");
    }
    for(re ll i=1;i<=n;i++) {
        if(!in[i]) {//被坑无数次 
            dp(i);
            for(re ll j=m;~j;j--) {
                for(re ll k=0;k<=j;k++) {
                    ans[j]=max(ans[j],ans[j-k]+d[i][0][k]);
                }
            }
        }
    }
    writeln(ans[m]);
//    FC();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/20020723YJX/p/9348020.html