bzoj 1017: [JSOI2008]魔兽地图DotR (树形DP+多重背包)
2017-05-25 17:50
489 查看
题目描述
传送门
题目大意:给出一棵树,树中的叶子节点可以直接购买,每个点有价格和数量限制,剩下的节点由他的所有儿子按照一定的数量合成,每个点有一个贡献值,给出M,问在花费不超过m的情况下贡献的最大值。(注意一个点如果用于合成,那么他本身的贡献不会再计算)
题解
这道题后来新加了一组数据,所有点都是B类装备无需合成,那么实际上就是一个多重背包。特判一下就好了。对于树,应该可以算是一种比较奇怪的树形依赖问题吧。
f[i][j][k] 表示到第i个点得到(合成)至少j个,花费是k的最大贡献。
叶子节点特殊处理一下。
对于每个点计算的时候,先枚举需要合成的数量x,然后g[i][j]表示到第i个儿子,花费是j,且一定能合成x个当前点now的最大贡献。
g[i][j]=max{g[i][j],g[i−1][j−k]+f[son[i]][k∗req[son[i]]][k]−k∗req[i]∗a[v[i]]}+x∗a[now]
其中a表示每个点的贡献,req[son[i]]表示合成一个now需要req[son[i]]个son[i]
推的时候注意边界即可。
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 2003 #define inf 1000000000 using namespace std; int tot,nxt ,point ,v ,req ; int n,m,dp[53][101][2003],f1 ,root,f[53][2003]; int mn ,sum ,val ,a ,c ,du ,head,tail,head1,tail1,q ,q1 ; char s[10]; void add(int x,int y,int z) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; req[tot]=z; //cout<<x<<" "<<y<<" "<<z<<endl; } void solve(int x,int fa) { bool pd=false; mn[x]=1000000000; for (int i=point[x];i;i=nxt[i]) { if (v[i]==fa) continue; solve(v[i],x); pd=true; mn[x]=min(mn[x],mn[v[i]]/req[i]); sum[x]+=val[v[i]]*req[i]; } if (!pd) mn[x]=min(c[x],m/val[x]),sum[x]=val[x]; } void dfs(int x,int fa) { bool pd=false; dp[x][0][0]=0; for (int i=point[x];i;i=nxt[i]){ if (v[i]==fa) continue; dfs(v[i],x); pd=true; } if (!pd) { for (int i=mn[x];i>=0;i--){ dp[x][i][i*val[x]]=i*a[x]; } for (int i=mn[x]-1;i>=0;i--) for (int j=0;j<=m;j++) dp[x][i][j]=max(dp[x][i][j],dp[x][i+1][j]); return; } for (int i=0;i<=n;i++) for (int j=0;j<=m;j++) f[i][j]=-inf; f[0][0]=0; for (int k=mn[x];k>=0;k--) { int tmp=0; for (int i=point[x];i;i=nxt[i]) { ++tmp; for (int j=0;j<=m;j++) { int l=k*req[i]; for (int t=l*val[v[i]];t+j<=m;t++) if (dp[v[i]][l][t]-l*a[v[i]]>=0) f[tmp][j+t]=max(f[tmp][j+t],f[tmp-1][j]+dp[v[i]][l][t]-l*a[v[i]]); } } for (int i=0;i<=m;i++) { if (f[tmp][i]>=0) dp[x][k][i]=max(dp[x][k][i],f[tmp][i]+a[x]*k); if (k!=mn[x]) dp[x][k][i]=max(dp[x][k+1][i],dp[x][k][i]); } } } int main() { freopen("bzoj_1017.in","r",stdin); freopen("bzoj_1017.out","w",stdout); scanf("%d%d",&n,&m); bool pd=true; for (int i=1;i<=n;i++) { scanf("%d%s",&a[i],s); if (s[0]=='A') { pd=false; int t; scanf("%d",&t); for (int j=1;j<=t;j++) { int x,y; scanf("%d%d",&x,&y); add(i,x,y); du[x]++; } } else scanf("%d%d",&val[i],&c[i]); } if (pd) { memset(f1,0,sizeof(f1)); for (int i=1;i<=n;i++) for (int j=0;j<val[i];j++) { head=tail=0; head1=tail1=0; for (int k=j,cnt=0;k<=m;k+=val[i],cnt++) { if (tail1-head1==c[i]+1) { if (q1[head1]==q[head]) head1++; head++; } int t=f1[k]-cnt*a[i]; q[++tail]=t; while (head1<tail1&&q1[tail1]<t) tail1--; q1[++tail1]=t; f1[k]=q1[head1+1]+cnt*a[i]; } } printf("%d\n",f1[m]); return 0; } root=1; for (int i=2;i<=n;i++) if (!du[i]) root=i; solve(root,0); for (int i=1;i<=n;i++) for (int j=0;j<=mn[i];j++) for (int k=0;k<=m;k++) dp[i][j][k]=-inf; dfs(root,0); int ans=0; for (int i=0;i<=m;i++) for (int j=0;j<=mn[root];j++) ans=max(ans,dp[root][j][i]); printf("%d\n",ans); }
相关文章推荐
- BZOJ1017 [JSOI2008]魔兽地图DotR 【树形dp + 背包dp】
- [BZOJ1017][JSOI2008][树形DP]魔兽地图DotR
- 【树形背包】【JSOI 2008】【bzoj 1017】魔兽地图DotR
- BZOJ.1017.[JSOI2008]魔兽地图(树形DP 背包DP)
- 【BZOJ-1017】魔兽地图DotR 树形DP + 背包
- bzoj1017 [JSOI2008]魔兽地图DotR(树形dp+背包dp+剪枝)
- [BZOJ1017][JSOI2008]魔兽地图DotR 树形dp
- 【树形Dp】【JSOI2008】【BZOJ1017魔兽地图DotR】
- bzoj 1017: [JSOI2008]魔兽地图DotR【树形dp+背包】
- bzoj1017 [JSOI2008]魔兽地图DotR 树形DP
- BZOJ1017: [JSOI2008]魔兽地图DotR
- BZOJ 1017: [JSOI2008]魔兽地图DotR
- 【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp
- [bzoj1017][JSOI2008]魔兽地图DotR【dp】
- bzoj1017 [JSOI2008]魔兽地图DotR
- 【JSOI 2008】【BZOJ 1017】魔兽地图DotR
- 【BZOJ】【1017】【JSOI2008】魔兽地图Dotr
- BZOJ1017: [JSOI2008]魔兽地图DotR
- bzoj1017: [JSOI2008]魔兽地图DotR
- bzoj 1017 : [JSOI2008]魔兽地图DotR