首页 > 代码库 > [dp] zoj 3769 Diablo III

[dp] zoj 3769 Diablo III

题目链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3769

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 nerd Yuzhi 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 least M Toughness. In addition, he want to finish the battle as soon as possible. That means the Damage should be as much as possible. Please help Yuzhi 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) and M (0 <= M <= 50000). The next N lines are the description of equipments. The i-th line contains a string Si and two integersDi and Ti (1 <= DiTi <= 50000). Si is the type of equipment in {"Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist", "Legs", "Feet", "Finger", "Shield", "Weapon", "Two-Handed"}. Di and Ti 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

2
1 25
Hand 30 20
5 25
Weapon 15 5
Shield 5 15
Two-Handed 25 5
Finger 5 10
Finger 5 10

Sample Output

-1
35

Author: YU, Zhi; JIANG, Kai
Source: The 14th Zhejiang University Programming Contest
Submit    Status

题目意思:

有13种装备,每种装备只能选一个,每种装备有一个伤害值和防御值,其中如果选Two-Handed的话就不能选Shield和Weapon,Finger可以选两个。求怎样选择,使得在防御值达到m的情况,伤害总值最大。

解题思路:

转化为背包。

这题是有限制的背包,但是如果把条件转化,就是个背包问题了。

可以把Shield和Weapon放到Two-Handed中,这样就满足Weapon、Shield和Two-Handed只会选一种,注意要把Shield+Weapon也当成一个。

Finger的话,可以枚举所有的两个再添加成一个。

注意本题不能只开一维,因为是要求不小于m的,只能枚举前面已经确定的防御值情况,去更新后面的情况。>m的状态记为m.

这题卡常数,要把各种的个数按大到小排个序,先把个数最多的那种先处理出来,不然会超时(当然如果不排序的话,从后往前推,也不会超时,估计是数据的原因)。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#include<cmath>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

map<string,int>myp;

#define Maxn 330

void init()
{
    myp["Head"]=1,myp["Shoulder"]=2,myp["Neck"]=3,myp["Torso"]=4;
    myp["Hand"]=5,myp["Wrist"]=6,myp["Waist"]=7,myp["Legs"]=8;
    myp["Feet"]=9,myp["Shield"]=10,myp["Weapon"]=11,myp["Finger"]=12;
    myp["Two-Handed"]=13;

}
struct PP
{
    int da,to;
}pp;
int n,m;
int dp[15][55000];
vector<PP>myv[15];

int Max(int a,int b)
{
    return a>b?a:b;
}

bool cmp(vector<PP> a,vector<PP> b)
{
    return a.size()>b.size();
}

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   //printf("%d\n",1<<14); //16384
   init();

   int t;

   scanf("%d",&t);
   while(t--)
   {
       scanf("%d%d",&n,&m);

       for(int i=1;i<=13;i++)
            myv[i].clear();

       for(int i=1;i<=n;i++)
       {
           string a;
           cin>>a>>pp.da>>pp.to;
           int in=myp[a];

            myv[in].push_back(pp);
            if(in==10||in==11)  //把shield和weapon都放到Two-Handed
                myv[13].push_back(pp);

       }
       //处理选择10+11的情况
       for(int i=0;i<myv[10].size();i++)
       {
           for(int j=0;j<myv[11].size();j++)
           {
               PP temp;
               pp.da=myv[10][i].da+myv[11][j].da;
               pp.to=myv[10][i].to+myv[11][j].to;

               myv[13].push_back(pp);
           }
       }
       //处理Fingers的情况 把任意的两个Fingers都枚举出来
       myv[10].clear();
       for(int i=0;i<myv[12].size();i++)
       {
           myv[10].push_back(myv[12][i]);
           for(int j=i+1;j<myv[12].size();j++)
           {
               PP temp;
               temp.da=myv[12][i].da+myv[12][j].da;
               temp.to=myv[12][i].to+myv[12][j].to;
               myv[10].push_back(temp);
           }
       }
       myv[11].clear();
       myv[11]=myv[13];
       sort(myv+1,myv+12,cmp);

       memset(dp,-1,sizeof(dp));
       dp[1][0]=0;

       for(int i=0;i<myv[1].size();i++)
       {
           int lim;
           if(myv[1][i].to>=m)
                lim=m;
           else
                lim=myv[1][i].to;
           dp[1][lim]=max(dp[1][lim],myv[1][i].da);
       }

       for(int i=2;i<=11;i++)
       {
           int sum=myv[i].size();
           for(int j=0;j<=m;j++)
           {

               if(dp[i-1][j]==-1)
                    continue;
               dp[i][j]=max(dp[i][j],dp[i-1][j]); //可以不选

               for(int k=0;k<sum;k++)
               {
                   int lim;

                   if(j+myv[i][k].to>=m)
                        lim=m;
                   else
                        lim=j+myv[i][k].to;

                   dp[i][lim]=Max(dp[i][lim],dp[i-1][j]+myv[i][k].da);

               }
           }
       }
       printf("%d\n",dp[11][m]);


   }
   return 0;
}