广东工业大学2016校赛决赛Problem B Sward Art Online(分组背包)

Description
    Krito为了打败第一层的boss - The eye of giant.SAO系统种一个人物可以装备4个物品,分别是左手武器,右手武器,首饰,盔甲,这些都可以增加一定的攻击力。注意每一种装备只能在所属的装备槽,双手武器会同时占用左手武器和右手武器的位置。还有有些首饰和特定的盔甲搭配可以产生不同的加成效果。在现在Krito有很多装备选择,当是他只有一定的金币,他想要获得最高的攻击力,问他应该怎么选择自己的装备才能使攻击力最高.

Input
第1行: 一个数T表示有多少个测试样例(T<=100)

对于每一个测试样例:
第1行:5个数m,a,b,c,d,表示Krito有m个金币,a种头盔,b种首饰,c种武器,d种双手武器(0<=m <=10000,0<=a,b,c,d<=100)
第2至2+a行: 表示可选的头盔,每行两个数,money,atk,表示这个物品的价格,和相应的攻击力加成(0<=money,atk<=100)
第3+a至3+a+b行:表示可选的首饰,每行四个数, money,atk,id,buff . id表示该件首饰如果和编号为id(从0开始)的头盔搭配可以获得buff的攻击力加成(|buff|<=100),id=-1和buff=-1表示没有加成效果
第4+a+b至4+a+b+c行: 表示可选的单手武器,可以装备在单手或者右手槽,注意每种武器只有一个,每行两个数,money,atk,表示这个物品的价格,和相应的攻击力加成(0<=money,atk<=100)
第5+a+b+c至5+a+b+c+d行: 表示可选的双手武器,每行两个数,money,atk,同上。

Output
输出能够获得的最大攻击力。
Sample Input

2
10 1 1 0 0
5 5
5 5 -1 -1
10 1 1 0 0
5 5
5 5 0 10
Sample Output
10
20


代码做了些优化,所以比较长,简单来说,思路就是:把{头盔,头盔+首饰,首饰}合成一组,{单手武器,两个单手武器,双手武器}合成一组。然后题目就变成有两组东西,每组最多只能选一种,问在只有m个金币的情况下,怎么选最优。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define UINF 18446744073709551615
#define MOD 1000000007
#define mem(a,b)  memset(a,b,sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;

int m,a,b,c,d;
int dp[405];
struct Head
{
    int money;
    int atk;
} head[105*105];
bool cmp2(Head a,Head b)
{
    if(a.money==b.money)
        return a.atk>b.atk;
    return a.money<b.money;
}

struct Hand
{
    int money;
    int atk;
}hand[105*105];
bool cmp3(Hand a,Hand b)
{
    return a.money<b.money;
}
bool cmp4(Hand a,Hand b)
{
    if(a.money==b.money)
        return a.atk>b.atk;
    return a.money<b.money;
}


int main()
{
    int t;
    int money,atk,id,buff;
    scanf("%d",&t);
    while(t--)
    {
        int Count=0;
        mem(dp,0);
        scanf("%d %d %d %d %d",&m,&a,&b,&c,&d);
        m=min(400,m);
        for(int i=0; i<a; i++)
        {
            scanf("%d %d",&money,&atk);
            head[Count].money=money;
            head[Count++].atk=atk;
        }
        for(int i=0; i<b; i++)
        {
            scanf("%d %d %d %d",&money,&atk,&id,&buff);
            if(money>m) continue;
            for(int j=0; j<Count; j++)
            {
                head[a].money=money+head[j].money;
                if(head[a].money>m) continue;
                if(j==id)
                    head[a++].atk=head[j].atk+buff+atk;
                else
                    head[a++].atk=head[j].atk+atk;
            }
            head[a].money=money;
            head[a++].atk=atk;
        }
        sort(head,head+a,cmp2);
        int now_Max=-1;
        Count=0;
        for(int i=0;i<a;i++)
        {
            if(head[i].atk>now_Max)
            {
                head[Count++]=head[i];
                now_Max=head[i].atk;
            }
        }
        a=Count;
        Count=0;
        for(int i=0;i<c;i++)
        {
            scanf("%d %d",&money,&atk);
            if(money>m) continue;
            hand[Count].money=money;
            hand[Count++].atk=atk;
        }
        c=Count;
        sort(hand,hand+c,cmp3);
        for(int i=0;i<Count;i++)
        {
            for(int j=i+1;j<Count;j++)
            {
                hand[c].money=hand[i].money+hand[j].money;
                if(hand[c].money>m) break;
                hand[c++].atk=hand[i].atk+hand[j].atk;
            }
        }
        for(int i=0;i<d;i++)
        {
            scanf("%d %d",&money,&atk);
            if(money>m) continue;
            hand[c].money=money;
            hand[c++].atk=atk;
        }
        sort(hand,hand+c,cmp4);
        now_Max=-1;
        Count=0;
        for(int i=0;i<c;i++)
        {
            if(hand[i].atk>now_Max)
            {
                hand[Count++]=hand[i];
                now_Max=hand[i].atk;
            }
        }
        c=Count;
        for(int i=m;i>=0;i--)
        {
            for(int j=0;j<a;j++)
            {
                if(head[j].money<=i)
                    dp[i]=max(dp[i],dp[i-head[j].money]+head[j].atk);
                else break;
            }
        }
        for(int i=m;i>=0;i--)
        {
            for(int j=0;j<c;j++)
            {
                if(hand[j].money<=i)
                    dp[i]=max(dp[i],dp[i-hand[j].money]+hand[j].atk);
                else break;
            }
        }
       printf("%d\n",dp[m]);
    }
    return 0;
}

/**************************************************************
    Language: C++
    Time:28 ms
    Memory:1740 kb
****************************************************************/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值