链接:点击打开链接
题意:有13种装备,每种装备只能选一个,每种装备有一个伤害值和防御值,其中如果选Two-Handed的话就不能选Shield和Weapon,Finger可以选两个。求怎样选择,使得在防御值达最小到m的情况下,伤害总值最大。
代码:
#include <queue>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
char cnt[50][50]={"Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist", "Legs", "Feet", "Finger", "Shield", "Weapon", "Two-Handed"};
int found(char s[]){
int i;
for(i=0;i<13;i++)
if(strcmp(s,cnt[i])==0)
return i;
}
struct node{
int x,y;
node(int a,int b){
x=a,y=b;
}
};
vector<node> G[20];
int cmp(vector<node> x,vector<node> y){
return x.size()>y.size();
}
int dp[305][50005];
int main(){
char str[105];
int n,m,i,j,k,t,a,b,tmp,len;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=0;i<13;i++)
G[i].clear();
for(i=0;i<n;i++){
scanf("%s %d %d",str,&b,&a);
G[found(str)].push_back(node(a,b));
}
tmp=G[9].size();
for(i=0;i<tmp;i++){
for(j=i+1;j<tmp;j++)
G[9].push_back(node(G[9][i].x+G[9][j].x,G[9][i].y+G[9][j].y));
} //将所有finger的情况合并
tmp=G[10].size();
for(i=0;i<tmp;i++){
for(j=0;j<G[11].size();j++)
G[10].push_back(node(G[10][i].x+G[11][j].x,G[10][i].y+G[11][j].y));
}
for(j=0;j<G[11].size();j++) //把shield和weapon合并
G[10].push_back(node(G[11][j].x,G[11][j].y));
for(j=0;j<G[10].size();j++) //并且和two-hand合并
G[12].push_back(node(G[10][j].x,G[10][j].y));
G[10].clear(),G[11].clear();
sort(G,G+13,cmp); //按照每种武器的数量从大到小排序
memset(dp,-1,sizeof(dp)); //可以快速增加有用的状态
dp[0][0]=0;
for(i=1;i<=13;i++){
len=G[i-1].size();
for(j=0;j<=m;j++){
dp[i][j]=max(dp[i][j],dp[i-1][j]);
if(dp[i-1][j]==-1)
continue;
for(k=0;k<len;k++){ //变成一个分组背包
tmp=min(m,j+G[i-1][k].x);
dp[i][tmp]=max(dp[i][tmp],dp[i-1][j]+G[i-1][k].y);
}
}
}
printf("%d\n",dp[13][m]);
}
return 0;
}