Diablo III
题目链接: ZOJ - 3769题意:小明要买一套装备去刷图,每个整套由{"Head"(头盔), "Shoulder"(肩甲), "Neck"(护颈), "Torso"(护甲), "Hand"(手套), "Wrist"(护腕), "Waist"(腰甲), "Legs"(绑腿), "Feet"(靴子), "Finger"(护指), "Shield"(护盾), "Weapon"(武器——大宝剑)}十二部分组成, 每部分的装备最多只能一件("Finger"(护指)可以装备两件), 还有一种装备——"Two-Handed"(攻防全能型装备), 一件此装备可以顶替 "Shield"(护盾),和"Weapon"(武器——大宝剑).,每件装备有两个属性——Damage(伤害) and Toughness(韧性)
由于不差钱, 小明要求装备的伤害附加值之和越高越好, 同时装备的韧性之和大于等于m;
求出最大伤害值;
比较麻烦的是Finger和Two-Handed, Shield , Weapon;Finger可以装备一件, 也可以装备两件, 而Two-Handed可以顶替 Shield 和 Weapon, 这两种状态难控制;
所以我们可以将Finger两两配对来表示一件,
同样的Shield和Weapon也可以用Two-Handed表示, Shield和Weapon相互匹配, 相当于一件Two-Handed;
dp[i][j] i表示第类件装备, j表示此时的Toughness;
由于最后求的是Toughness大于m时的最大Damage, 所以当Toughness大于m时, 结果就存到m中;
状态转移方程:
dp[i][j+t]=max(dp[i][j+t], d[i+1][j]+d);
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
string equip[]={"Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist",
"Legs", "Feet", "Finger", "Shield", "Weapon", "Two-Handed"};
struct node{
int d, t;
};
vector<node> vec[15];
int get_id(string s){
for(int i=0; i<13; i++){
if(s==equip[i]) return i;
}
return -1;
}
int dp[15][50010];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m;
string s;
for(int i=0; i<13; i++) vec[i].clear();
node tmp;
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++){
cin >> s >> tmp.d >> tmp.t;
int z=get_id(s);
vec[z].push_back(tmp);
if(z==10||z==11) vec[12].push_back(tmp);//如果是"Shield"或"Weapon", 存到"Two-Handed"中;
}
//将"Shield"和"Weapon"两两结合当作"Two-Handed";
for(int i=0; i<vec[10].size(); i++){
for(int j=0; j<vec[11].size(); j++){
tmp.d=vec[10][i].d+vec[11][j].d;
tmp.t=vec[10][i].t+vec[11][j].t;
vec[12].push_back(tmp);
}
}
//将Finger两两结合;
vec[10].clear();//"Shield"清空, 用来存Finger;
for(int i=0; i<vec[9].size(); i++){
vec[10].push_back(vec[9][i]);
for(int j=i+1; j<vec[9].size(); j++){
tmp.d=vec[9][i].d+vec[9][j].d;
tmp.t=vec[9][i].t+vec[9][j].t;
vec[10].push_back(tmp);
}
}
vec[9].clear();//Finger已经转移到vec[10]中, 此处清空;
memset(dp, -1, sizeof(dp));//-1表示无此状态;
int vt, vd;
dp[11][0]=0;
//"Two-Handed"单独处理;
for(int i=0; i<vec[12].size(); i++){
tmp=vec[12][i];
vt=tmp.t>=m?m:tmp.t;
vd=tmp.d;
dp[11][vt]=max(dp[11][vt], vd);
}
for(int i=10; i>=0; i--){
for(int j=0; j<=m; j++){
dp[i][j]=max(dp[i][j], dp[i+1][j]);
if(dp[i+1][j]==-1) continue;//i+1没有j这个状态;
for(int k=0; k<vec[i].size(); k++){
tmp=vec[i][k];
vt=(tmp.t+j)>=m?m:(tmp.t+j);
vd=tmp.d;
dp[i][vt]=max(dp[i][vt], dp[i+1][j]+vd);
}
}
}
printf("%d\n", dp[0][m]);
}
return 0;
}