树上背包
题目传送门
首先,有没有哪位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#include #include #include #include #include #include #include #include #include<set> #include
#include #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 "); //#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' 'a')&&('Z' '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; }