zoj3769(分组背包)

链接:点击打开链接

题意:有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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值