http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3769
题意:
有13种装备,每种装备值可以穿戴一种,特殊的就是双手武器和单手武器,双手武器和单手武器+盾只能选择一种,戒指可以双手各戴一个。每个装备都有一个攻击值和防御值,现在要在防御值至少到达m的情况下可以达到的最大攻击力。
思路:
分组背包题目。
把单手武器和盾组合起来放到双手武器当中,戒指也需要两两组合。
接下来就是一个分组背包了,比较重要的是这道题目需要开二维数组,因为题目要求的是至少要达到m的容量,如果超过了m容量,就需要按m来算。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn = + ; int n,m;
int d[][];
vector<pll> v[];
map<string,int> ID; void init()
{
ID["Head"] = ; ID["Shoulder"] = ; ID["Neck"] = ;
ID["Torso"] = ; ID["Hand"] = ; ID["Wrist"] = ;
ID["Waist"] = ; ID["Legs"] = ; ID["Feet"] = ;
ID["Finger"] = ; ID["Shield"] = ; ID["Weapon"] = ;
ID["Two-Handed"] = ;
} bool cmp(const vector<pll> a, const vector<pll> b)
{
return a.size()>b.size();
} int main()
{
//freopen("in.txt","r",stdin);
init();
int T;
scanf("%d",&T);
while(T--)
{
for(int i=;i<;i++) v[i].clear(); scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int D,T; string s;
cin>>s>>D>>T;
v[ID[s]].push_back(make_pair(D,T));
if(ID[s]== || ID[s]==) v[].push_back(make_pair(D,T));
} //合并单手武器和盾牌
for(int i=;i<v[].size();i++)
{
for(int j=;j<v[].size();j++)
{
v[].push_back(make_pair(v[][i].first+v[][j].first,v[][i].second+v[][j].second));
}
} v[].clear();
v[].clear(); //合并戒指并且储存在v[10]中
int len=v[].size();
for(int i=;i<len;i++)
{
for(int j=i+;j<len;j++)
{
v[].push_back(make_pair(v[][i].first+v[][j].first,v[][i].second+v[][j].second));
}
} memset(d,-,sizeof(d));
sort(v+,v+,cmp); d[][]=;
for(int i=;i<=;i++)
{
for(int j=;j<=m;j++)
{
d[i][j]=max(d[i][j],d[i-][j]); //第i组的状态有第i-1组状态而来
if(d[i-][j]==-) continue;
for(int k=;k<v[i].size();k++)
{
int tmp=min(v[i][k].second+j,m); //如果容量超过了m,那么就按m来算
d[i][tmp]=max(d[i][tmp],d[i-][j]+v[i][k].first); //由第i-1组更新
}
}
}
printf("%d\n",d[][m]);
}
return ;
}