zoj 3769 Diablo III (分组背包+优化+背包细节)

来源:互联网 发布:广东淘宝司法拍卖网站 编辑:程序博客网 时间:2024/05/16 09:57
Diablo III

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Diablo III is an action role-playing video game. A few days ago, Reaper of Souls (ROS), the new expansion of Diablo III, has been released! On hearing the news, the crazy video game nerdYuzhi shouted: "I'm so excited! I'm so excited! I wanna kill the Diablo once more!"

The ROS introduced a lot of new features and changes. For example, there are two new attributes for players in the game: Damage and Toughness. The attribute Damage indicates the amount of damage per second you can deal and the Toughness is the total amount of raw damage you can take.

To beat the Diablo, Yuzhi need to select the most suitable equipments for himself. A player can carry at most 13 equipments in 13 slots: Head, Shoulder, Neck, Torso, Hand, Wrist, Waist, Legs, Feet, Shield, Weapon and 2 Fingers. By the way, there is a special type of equipment: Two-Handed. A Two-Handed equipment will occupy both Weapon and Shield slots.

Each equipment has different properties on Damage and Toughness, such as a glove labeled "30 20" means that it can increase 30 Damage and 20 Toughness for the player who equips it in the Hand slot. The total Damage and Toughness is the sum of Damage and Toughness of all equipments on the body. A player without any equipments has 0 Damage and 0 Toughness.

Yuzhi has N equipments stored in his stash. To fight against the Diablo without lose the battle, he must have at leastM Toughness. In addition, he want to finish the battle as soon as possible. That means the Damage should be as much as possible. Please helpYuzhi to determine which equipments he should take.

Input

There are multiple test cases. The first line of input is an integer T indicates the number of test cases. For each test case:

The first line contains 2 integers N (1 <= N <= 300) andM (0 <=M <= 50000). The next N lines are the description of equipments. The i-th line contains a stringSi and two integersDi and Ti (1 <=Di,Ti <= 50000). Si is the type of equipment in {"Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist", "Legs", "Feet", "Finger", "Shield", "Weapon", "Two-Handed"}.Di andTi are the Damage and Toughness of this equipment.

Output

For each test case, output the maximum Damage that Yuzhi can get, or -1 if he can not reach the required Toughness.

Sample Input

21 25Hand 30 205 25Weapon 15 5Shield 5 15Two-Handed 25 5Finger 5 10Finger 5 10

Sample Output

-135


题意:

给出13类装备,每种装备都有攻击力和防御值,每种装备只允许选择一个,求满足防御值至少在M的情况下,攻击力最大为多少.有几个条件:13种装备里如果选择了双手装备,就不能选择武器和护盾了,还有戒指可以双手各带一个.


思路:

将武器和护盾合并为双手装备,将两个戒指合并,那么就只有11种装备了,就是熟悉的分组背包了。

dp[i][j]-到第i个物品防御力为j的时候的最大的攻击力。

由于合并时物品数会变很多,比如有100个武器,200个护盾的话那么这组物品就有20000个了。所以很容易超时,采取的方案是将物品按照个数的大小排序,按照这个顺序背包,因为在前面的时候可行状态会很少,所以很多时候就只进行了两重循环,节约了时间。

ps:

采用一维的背包容易WA的原因在于用dp[k](前一个状态的)更新dp时,更新了自己dp[k],然后继续用dp[k]来更新,所以就产生了错误,应该用一个值记下dp[k]来更新dp.

采用二维的背包注意要将前面一组的合法状态都转移到当前组来


代码:(一维背包)

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <string>#include <map>#include <stack>#include <vector>#include <set>#include <queue>#pragma comment (linker,"/STACK:102400000,102400000")#define maxn 1005#define MAXN 100005#define OO (1<<31)-1#define mod 1000000009#define INF 0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-6typedef long long ll;using namespace std;string xx[14]={    "Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist",    "Waist", "Legs", "Feet", "Shield", "Weapon","Finger",    "Two-Handed"},ss;int n,m,ans,ma;int a[11]= {0,1,2,3,4,5,6,7,8,11,12};struct node{    int sz,id;}xxx[12];int dp[50005];char s[100];vector<int>D[14],T[14];int Find(string ts){    int i;    for(i=0; i<13; i++)    {        if(ts==xx[i]) return i;    }}bool cmp(node x,node y){    return x.sz>y.sz;}void presolve(){    int i,j,t,d,sz;    sz=D[11].size();    for(i=0; i<sz; i++)    {        for(j=i+1; j<sz; j++)        {            d=D[11][i]+D[11][j];            t=T[11][i]+T[11][j];            D[11].push_back(d);            T[11].push_back(t);        }    }    for(i=0;i<D[9].size();i++)    {        D[12].push_back(D[9][i]);        T[12].push_back(T[9][i]);    }    for(i=0;i<D[10].size();i++)    {        D[12].push_back(D[10][i]);        T[12].push_back(T[10][i]);    }    for(i=0; i<D[9].size(); i++)    {        for(j=0; j<D[10].size(); j++)        {            d=D[9][i]+D[10][j];            t=T[9][i]+T[10][j];            D[12].push_back(d);            T[12].push_back(t);        }    }    for(i=0;i<=10;i++)    {        xxx[i].id=a[i];        xxx[i].sz=D[a[i]].size();    }    sort(xxx,xxx+11,cmp);}void solve(){    int i,j,t,k,p,st,val,ai,sz,haha;    for(i=0; i<=m; i++) dp[i]=-INF;    dp[0]=0;    for(i=0; i<=10; i++)    {        ai=xxx[i].id;        sz=D[ai].size();        for(k=m; k>=0; k--) // 从前往后推 枚举此时k值 因为>m的都记为m了 所以枚举后一个k值会出现问题         {            if(dp[k]<0) continue ;            haha=dp[k];    // 不能自己更新自己再更新别人 得记录自己            for(p=0; p<sz; p++)            {                val=min(m,k+T[ai][p]);                dp[val]=max(dp[val],haha+D[ai][p]);            }        }    }    ans=max(-1,dp[m]);    printf("%d\n",ans);}int main(){    int i,j,t,dd,tt,x,y;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        for(i=0; i<14; i++) D[i].clear(),T[i].clear();        ma=0;        for(i=1; i<=n; i++)        {            scanf("%s%d%d",s,&dd,&tt);            ss=s;            x=Find(ss);            D[x].push_back(dd);            T[x].push_back(tt);        }        presolve();        solve();    }    return 0;}







0 0
原创粉丝点击