链接:点击打开链接
题意:有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; }