其实这题是我从noip前就开始做的。。。那个时候打的Pascal,一直TLE,转了C++之后我又写了一遍,A了。。。

辛酸史:

                    

题目描述:

DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars。

DotR里面的英雄只有一个属性——力量。他们需要购买装备来提升自己的力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力量值之和。装备分为基本装备和高级装备两种。基本装备可以直接从商店里面用金币购买,而高级装备需要用基本装备或者较低级的高级装备来合成,合成不需要附加的金币。装备的合成路线可以用一棵树来表示。

比如,Sange and Yasha的合成需要Sange,Yasha和Sange and Yasha Recipe Scroll三样物品。其中Sange又要用Ogre Axe, Belt of Giant Strength和 Sange Recipe Scroll合成。每件基本装备都有数量限制,这限制了你不能无限制地合成某些性价比很高的装备。

现在,英雄Spectre有M个金币,他想用这些钱购买装备使自己的力量值尽量高。你能帮帮他吗?他会教你魔法Haunt(幽灵附体)作为回报的。

数据范围:物品数(n)<=51,金币数(m)<=2000,限购数量(limit)<=100。

思路分析:

可以说是一道树上背包DP吧。

观察题目,注意到:限购数量是题目的关键,对于一个物品,它合成几件,或是把几件用于父亲装备的合成,是题目恶心的地方,既然这样的话我们就把它设计到状态里面。然后再看看数据范围,限购小于等于100——很明显了,出题人就是想让我们把限购数量放进状态里面。再和普通的背包结合一下,得到状态,f[u][i][j]表示:对于以u为根的子树,在以u为根的子树上,我们投入i个金币,并且把j个物品u用于父亲装备的合成,以u为根的子树能产生的最大力量值。

然后我们还需要一个g数组来辅助f数组的转移。g[i][j]表示:对于u的前i个儿子装备,在以它们为根的子树中投入j个金币,能得到的最大力量值。

转移时我们需要枚举的很重要的一环就是:制作几个u装备,从而让整个转移能够顺利地进行下去,我们把它设为l。

得到g数组的转移:g[i][j]=max(g[i][j],g[i-1][j-k]+f[v][k][l*need])       其中v为u的第i个儿子,而need则为制作一个装备u需要几个装备v,k为在以v为根的子树中花费k个金币。

通过g数组的转移,继而得到f数组的转移:f[u][i][j]=max(f[u][i][j],g[siz[u]][i]+w[u]*(l-j))       其中siz[u]表示u有几个儿子。

最后求答案的时候我们又需要一个dp数组来求解。(嗯,没错,一道题目,三个背包dp,我也不得不佩服出题人了——你是真TM的毒瘤!)

最后这个就是最简单的背包dp了(如果这个都想不到的话,建议你前往xx省xx市实验学校,和某张姓老师学习一段时间)

状态dp[i][j],表示前i个“终极装备”(终极装备就是无法用于合成的装备),花费j个金币,能得到的最大力量值。转移的时候枚举一下在第i个装备上花费多少金币就可以了,具体不懂的话还是看代码吧,太简单了,也不想多讲了。

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int f[55][2005][105],g[55][2005],dp[55][2005];
int a[55][55],need[55][55],limit[55],cost[55],w[55],siz[55];
bool root[55],son[55];
int n,m;
void dfs(int u){
if (!son[u]){
limit[u]=min(limit[u],m/cost[u]);
for (int i=0;i<=limit[u];i++)
for (int j=0;j<=i;j++)
f[u][i*cost[u]][j]=w[u]*(i-j);
return;
}
limit[u]=inf;
for (int i=1;i<=siz[u];i++){
dfs(a[u][i]);
cost[u]+=cost[a[u][i]]*need[u][i];
limit[u]=min(limit[u],limit[a[u][i]]/need[u][i]);
}
limit[u]=min(limit[u],m/cost[u]);
memset(g,-0x3f,sizeof(g));
g[0][0]=0;
for (int l=limit[u];l>=0;l--){ //这里倒着枚举l,是为了避免多次给g数组赋初值
for (int i=1;i<=siz[u];i++)
for (int j=0;j<=m;j++)
for (int k=0;k<=j;k++)
g[i][j]=max(g[i][j],g[i-1][j-k]+f[a[u][i]][k][l*need[u][i]]);
for (int i=0;i<=l;i++)
for (int j=0;j<=m;j++)
f[u][j][i]=max(f[u][j][i],g[siz[u]][j]+w[u]*(l-i));
}
}
int main(){
memset(f,-0x3f,sizeof(f));
scanf("%d%d",&n,&m);
int nn,ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&w[i]);
char ch[3]; scanf("%s",&ch);
if (ch[0]=='A'){
scanf("%d",&nn);
for (int j=1;j<=nn;j++) scanf("%d%d",&a[i][j],&need[i][j]),root[a[i][j]]=true;
son[i]=true; siz[i]=nn;
} else scanf("%d%d",&cost[i],&limit[i]);
}
int now=0;
for (int i=1;i<=n;i++)
if (!root[i]){
dfs(i); now++;
for (int j=0;j<=m;j++)
for (int k=0;k<=j;k++)
dp[now][j]=max(dp[now][j],dp[now-1][j-k]+f[i][k][0]);
}
for (int i=0;i<=m;i++) ans=max(ans,dp[now][i]);
printf("%d\n",ans);
return 0;
}

JSOI 2008 【魔兽地图】的更多相关文章

  1. JSOI 2008 魔兽地图

    题目描述 DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) ...

  2. 【BZOJ-1017】魔兽地图DotR 树形DP + 背包

    1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1566  Solved: 705[Submit][S ...

  3. 1017: [JSOI2008]魔兽地图DotR - BZOJ

    Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Anc ...

  4. BZOJ 1017 魔兽地图

    Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Anc ...

  5. BZOJ [JSOI2008]魔兽地图DotR

    1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1243  Solved: 532[Submit][S ...

  6. 【百度地图API】如何制作一张魔兽地图!!——CS地图也可以,哈哈哈

    原文:[百度地图API]如何制作一张魔兽地图!!--CS地图也可以,哈哈哈 摘要: 你玩魔兽不?你知道如何做一张魔兽地图不?! 快来看此文吧! ---------------------------- ...

  7. [BZOJ]1017 魔兽地图DotR(JSOI2008)

    BZOJ第一页做着做着就能碰到毒题,做到BZOJ1082小C就忍了,没想到下一题就是这种东西.这种题目不拖出来枭首示众怎么对得起小C流逝的青春啊. Description DotR (Defense ...

  8. [JSOI2008]魔兽地图(树形dp)

    DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allst ...

  9. 【BZOJ1017】[JSOI2008]魔兽地图(动态规划)

    [BZOJ1017][JSOI2008]魔兽地图(动态规划) 题面 BZOJ 洛谷 题解 状态设一下,\(f[i][j][k]\)表示第\(i\)个物品,有\(j\)个用于合成,总花费为\(k\)的最 ...

随机推荐

  1. hdu 4010 Lct动态链接树

    #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include & ...

  2. 小程序开发-Canvas画布组件

    Canvas画布 基本使用方法: 在wxml中添加canvas组件 <canvas canvas-id='canvasDemo' class='demo'></canvas> ...

  3. 08_线程间通信 ITC

    1.线程间的通信方式 1.共享全局变量 2.线程队列(queue) 3.信号量(Semaphore) 2.共享全局变量进行通信 from threading import Thread import ...

  4. Spring源码学习(六)-spring初始化回调方法源码学习

    1.spring官方指定了三种初始化回调方法 1.1.@PostConstruct.@PreDestory 1.2.实现 InitializingBean DisposableBean 接口 1.3. ...

  5. 2018.12.08【NOIP提高组】模拟B组总结(未完成)

    2018.12.08[NOIP提高组]模拟B组总结 diyiti 保留道路 进化序列 B diyiti Description 给定n 根直的木棍,要从中选出6 根木棍,满足:能用这6 根木棍拼出一个 ...

  6. 浅谈Java 线程池原理及使用方式

    一.简介 什么是线程池? 池的概念大家也许都有所听闻,池就是相当于一个容器,里面有许许多多的东西你可以即拿即用.java中有线程池.连接池等等.线程池就是在系统启动或者实例化池时创建一些空闲的线程,等 ...

  7. JavaScript 伪Ajax请求

    伪Ajax 通过iframe以及form表单,可以实现伪Ajax的方式. 并且它的兼容性是最好的. iframe iframe标签能够获取一个其他页面的文档内容,这说明它内部肯定是发送了一个请求,并且 ...

  8. Spring源码解析 | 第一篇 :IntelliJ IDEA2019.3编译Spring5.3.x源码

    前言 工欲善其事必先利其器.学习和深读Spring源码一个重要的前提:编译源码到我们的本地环境.这样方便我们在本地环境添加注释.断点追踪.查看类或接口的继承关系等等,更加高效的学习Spring源码.个 ...

  9. vue 中后台 列表的增删改查同一解决方案

    查看 & 查询 常⻅业务列表⻚都是由 搜索栏 和 数据列表 组成. 其中: 搜索栏包含 搜索条件 . 新增 . 批量xx . 导出 等对 数据列表 全局操作功能项. 数据列表包含 分⻚ 和每条 ...

  10. zookeeper(4) 网络

    zookeeper底层通过NIO进行网络传输,如果对NIO不是很熟悉,先参见java NIO.下面我们来逐步实现基于NIO的zookeeper实现,首先我们要定义应用层的通信协议. 传输协议 请求协议 ...