题目链接:https://vjudge.net/problem/ZOJ-3769

题意:现在你要去打怪,你有13种装备,每件装备会有伤害和防御两种属性,一般来说,每种装备只可以装备一件,但是特别的,戒指(Finger)你可以同时装备两个,左右手各一个,然后对于“Two-Handed”类的装备,如果你装备这种装备,那么你就不可以装备"Shield", "Weapon"这两种,反之,如果你装备了"Shield", "Weapon"中的任意一种,那么你就不可以装备“Two-Handed”类的装备,现在需要我们求出在达到m点以上防御值的情况下可以达到的最大攻击值。如果无法达到m点防御值,则输出-1。

思路:这题可以转化为分组背包,但是又两个问题要解决,一个是Finger类装备,我们可以把Finger类的装备两两组合,加入Finger类里面,这样就把两个Finger类的装备转化为了一个,然后对于"Shield", "Weapon"这两类,我们也是可以两两组合加入“Two-Handed”类里面去的,当然,为了避免其中一种装备的数量为0,所以可以先将"Shield", "Weapon"这两类分别加入“Two-Handed”,然后在加入两两组合的。我一开始是用结构体数组储存的,一直超时,看了大佬博客,说要先处理数量多的那一类,这样可以节省时间,觉得有道理,但是用结构体数组改了还是一直超时(果然,大佬的代码和我的就是不一样),最后重写代码,改成和他们一样用vector储存就过了,不知道为啥。如果有谁知道的,可以提醒一下我,感谢感谢。

这里开二维数组,其中把防御看做背包容量,但是我们不知道背包容量的上限,题目只说了要大于等于m点防御值,所以我们把m以上的都看成m(为啥别人脑洞就这么大),由于在第k组拿装备的时候需要知道第k-1组的值,所以状态转移方程就是dp[k][i+w[j]]=max(dp[k][i+w[j]],dp[k-1][i]+v[j])。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 50005
/*struct point{
int u,w;
};
bool operator <(const point &s1,const point &s2)
{
if(s1.v!=s2.v)
return s1.v>s2.v;
else
return s1.u>s2.u;
}*/
struct node{
int v,w;
};
int n,m,k,t;
map<string,int>mp;
vector<node>ve[];
string ss[]={" ","Two-Handed","Finger", "Head", "Shoulder", "Neck", "Torso",
"Hand", "Wrist", "Waist", "Legs","Feet", "Shield", "Weapon"};
int dp[][maxn];
void init()
{
for(int i=;i<=;i++){//给装备编号
mp[ss[i]]=i;
}
}
int main()
{
init();
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=;i<=;i++){
ve[i].clear();
}
string s;
int w,v;
for(int i=;i<=n;i++){
cin>>s>>v>>w;
int id=mp[s];
ve[id].push_back((node){v,w});
}
memset(dp,-,sizeof(dp));//初始化所有状态都不可达
dp[][]=;//初始化 for(int i=;i<ve[].size();i++){//"Shield", "Weapon"合并到“Two-Handed”
ve[].push_back(ve[][i]);
}
int num1=ve[].size();
int num2=ve[].size();
for(int i=;i<num2;i++){
ve[].push_back(ve[][i]);
for(int j=;j<num1;j++){
ve[].push_back((node){ve[][i].v+ve[][j].v,ve[][i].w+ve[][j].w});
}
} num1=ve[].size();
for(int i=;i<num1;i++){//"Finger"合并
for(int j=i+;j<num1;j++){
ve[].push_back((node){ve[][i].v+ve[][j].v,ve[][i].w+ve[][j].w});
}
} for(int k=;k<=;k++){//枚举组
for(int i=;i<=m;i++){//枚举防御值
dp[k][i]=max(dp[k][i],dp[k-][i]);//现在状态的初值从前一状态来
if(dp[k-][i]==-)//如果前一状态不可达
continue;
for(int j=;j<ve[k].size();j++){//如果前一状态可以到达,那么可以在前一状态的基础上在当前组
//拿一件装备
int min1=min(m,i+ve[k][j].w);
dp[k][min1]=max(dp[k][min1],dp[k-][i]+ve[k][j].v);
}
}
}
cout<<dp[][m]<<endl;
}
return ;
}

结构体数组一直超时的代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 50005
/*struct point{
int u,w;
};
bool operator <(const point &s1,const point &s2)
{
if(s1.w!=s2.w)
return s1.w>s2.w;
else
return s1.u>s2.u;
}*/
map<string,int>mp;
int dp[][maxn];
int n,m,k,t;
struct node{
int num;
int w[];
int v[];
}zu[];
string s[]={" ", "Two-Handed"," ","Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist",
"Legs", "Feet", "Finger", "Shield", "Weapon"};
void init()
{
for(int i=;i<=;i++)
{
mp[s[i]]=i;
}
}
void combine_finger()
{
int c=zu[].num;
if(c==)
return;
if(c==)
{
zu[].num++;
zu[].w[]=zu[].w[];
zu[].v[]=zu[].v[];
return;
}
for(int i=;i<c;i++){
for(int j=i+;j<=c;j++){
zu[].num++;
int k=zu[].num;
zu[].w[k]=zu[].w[i]+zu[].w[j];
zu[].v[k]=zu[].v[i]+zu[].v[j];
}
}
return;
}
void combine_two()
{
int a=zu[].num;
int b=zu[].num;
for(int i=min(a,);i<=a;i++){
for(int j=min(b,);j<=b;j++){
zu[].num++;
int c=zu[].num;
zu[].w[c]=zu[].w[i]+zu[].w[j];
zu[].v[c]=zu[].v[i]+zu[].v[j];
}
}
return;
}
int main()
{
init();
scanf("%d",&t);
while(t--)
{
memset(dp,,sizeof(dp));
scanf("%d%d",&n,&m);
string ss,w,v;
int a,b;
for(int i=;i<=n;i++){
cin>>ss>>a>>b;
int id=mp[ss];
zu[id].num++;
int c=zu[id].num;
zu[id].v[c]=a;
zu[id].w[c]=b;
}
combine_finger();
combine_two();
memset(dp,-,sizeof(dp));
dp[][]=;
for(int k=;k<=;k++){
for(int i=;i<=m;i++){
dp[k][i]=max(dp[k][i],dp[k-][i]);
if(dp[k-][i]==-)
continue;
for(int j=;j<=zu[k].num;j++){
int min1=min(m,i+zu[k].w[j]);
dp[k][min1]=max(dp[k][min1],dp[k-][i]+zu[k].v[j]);
}
}
}
cout<<dp[][m]<<endl;
}
return ;
}

转化为分组背包 zoj 3769的更多相关文章

  1. HDU 4341 Gold miner(分组背包)

    题目链接 Gold miner 目标是要在规定时间内获得的价值总和要尽可能大. 我们先用并查集把斜率相同的物品分在同一个组. 这些组里的物品按照y坐标的大小升序排序. 如果组内的一个物品被选取了,那该 ...

  2. ZOJ 3769 Diablo III(分组背包)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3769 题意:有13种装备,每种装备值可以穿戴一种,特殊的就是双手武器和单手 ...

  3. HDU 1712 ACboy needs your help(分组背包)

    题意:给你n的课程组,每个课程组有m个课程,每个课程有一个完成时间与价值.问在m天内每组课程组最多选择一个,这样可以得到的最大价值是多少 题解:分组背包,其实就是每个课程组进行01背包,再在课程组内部 ...

  4. hdu 1712 (分组背包入门)

    http://acm.hdu.edu.cn/showproblem.php?pid=1712 问题 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].这些物品被划分为若干组, ...

  5. #分组背包 Educational Codeforces Round 39 (Rated for Div. 2) D. Timetable

    2018-03-11 http://codeforces.com/contest/946/problem/D D. Timetable time limit per test 2 seconds me ...

  6. HDU - 1712 - ACboy needs your help 【分组背包】

    <题目链接> 题目大意:有n个课程,现在花M天来学习这些课程,学习每个课程花的天数所得到的价值不同,求M天怎么分配学习才能得到的价值最大.(这些课程得到的价值和所花天数的关系由矩阵给出) ...

  7. HDU1712:ACboy needs your help(分组背包模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=1712 Problem Description ACboy has N courses this term, an ...

  8. HDU 1712 ACboy needs your help(分组背包入门题)

    http://acm.hdu.edu.cn/showproblem.php?pid=1712 题意: 有个人学习n门课程,a[i][j]表示用j分钟学习第i门课程所能获得的价值,背包容量为一共有m时间 ...

  9. 洛谷P1273 有线电视网 【树上分组背包】

    题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从 ...

随机推荐

  1. SQL Server MSSQLSERVER 服务无法启动解决方案

    打开sql配置工具下的sql server configuration manager,然后将VIA协议禁用.

  2. xcode 自动签名、手动签名

    手动签名:需要手动生成p12文件(私钥),然后将对应的公钥上传到开发者网站,生成证书,进一步生成对应的描述文件,然后在xcode中手动指定描述文件,这个描述文件中包含与本地p12文件对应的证书. 自动 ...

  3. windows7 安装虚拟机,xsheel连接不上的问题,记录一下

    安装了好久,一直连接不上...,原来是网络没开..重新安装设置就可以了!!!记录一下

  4. MySQL查询优化(转)

    在分析性能欠佳的查询时,应考虑: 1) 应用程序是否正获取超过需要的数据,即访问了过多的行或列. 2) Mysql服务器是否分析了超过需要的行. 如果发现访问的数据行数很大,而生成的结果中数据行很少, ...

  5. 静态函数造成GC的原因

    有时候用deep profiling查看GC时会发现:一个父函数有GC,展开子层级看到一个很奇怪的 CX::ctor,表示CX进行了构造,然后打开父函数代码却完全看不到有new CX的地方,这个时候可 ...

  6. DO and DOES Reduction

    DO and DOES Reduction Share Tweet Share Tagged With: DO and DOES Reductions ‘Do’ and ‘does’ can be r ...

  7. week5 04 npm run build

    上期 我们完成了nodeserver的创建 用的是express genrealtor那个工具 我们在server端执行 起来了 然后我们改一下 删一下 我们觉着暂时没用的东西 首先去app.js程序 ...

  8. C++ : 窗口变化相关消息 OnSize、OnSizing和OnGetMinMaxInfo,onsizeonsizing

    个消息分别是:WM_SIZE.WM_SIZING.WM_GETMINMAXINFO:分别对应相应的处理函数:OnSize.OnSizing.OnGetMinMaxInfo. 当窗口大小发生变化时,响应 ...

  9. SQL Server GROUP BY 后 拼接 字符串

    原文地址:https://blog.csdn.net/u010673842/article/details/79637618 select ID, ,,'') from class a group b ...

  10. java中Integer和int的区别(转)

    int和Integer的区别 1.Integer是int的包装类,int则是java的一种基本数据类型 2.Integer变量必须实例化后才能使用,而int变量不需要 3.Integer实际是对象的引 ...