您的位置:首页 > 其它

ZOJ 3769 —— Diablo III(背包,DP)

2014-04-06 21:43 471 查看
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3769

额,题目有点长的样子。

大概意思就是说人身上有13个地方可以装备道具,其中两个注意点,一个是fingers,这说明有两根手指可以装备。。。另一个是Two-Handed这种装备会同时占据Weapon和Shield两种道具的装备位置,同一位置只能装备一个道具,不同位置不会影响。

每种道具都会有damage和toughness两个参数,题目要问的是,从中选出一些装备,那么人物的damage值和toughness就是所选装备对应的和,在保证toughness不小于m的情况下,求最大的damage,如果无法达到toughness,就输出-1。

这个背景还是挺经典的背包问题,只是套上一些限制。

如果按照装备的类型分类,最多就13类,先不管前面说的两个注意点,如果这13类之间是没有影响的,dp[i][j]来表示取到第i 类物品,总toughness是j 时候,最优伤害值。

那么对于第i 类物品,假设当前考虑到其中的第k件物品,两个参数分别是d和t,那么枚举前一类物品能够达到的所有状态dp[i-1][j],可以推出新的状态dp[i][j+t] = max(dp[i][j+t], dp[i][j]+d)

而在这个问题中,因为我们只需要达到m,所以对于j+t超过m情况,可以简单记录为m。

然后建立在这种思路的基础上,我们再来考虑那两个条件:

1、对于两个手指的,无论是只装备一根手指,还是装备了两只,都用手指这一类来表示,那么,所有手指装备本身当作只装备一根手指,装备两只的你就两两枚举下吧;

2、对于Weapon和Shield两种道具以及Two-Handed,我们还是把它们当成一种来处理,首先各自肯定当成一件物品,然后就是枚举Weapon和Shield的搭配了;

这样处理之后,按照我们的递推式,同类物品之间是不会有冲突的,所以以上处理过后,题目的限制条件就不见了。。。

然后我们就可以快乐地AC了~~

PS:因为扫物品名称列表的时候,几个特殊处理的物品都是在后面,所以具体到实现的时候,我是从后往前推的。。。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define pb push_back
char name[20][20]={"Head","Shoulder","Neck","Torso","Hand","Wrist","Waist","Legs","Feet","Finger","Shield","Weapon","Two-Handed"};
int t, n, m;
struct Goods{
int dmg, tou;
}g;
int getnum(char* s){
for(int i=0; i<13; i++) if(strcmp(s, name[i])==0)   return i;
}
vector<Goods> V[13];//用vector来存储同类物品
int dp[13][50001], vd, vt;
int main(){
int i, j, k;
char s[20];
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
for(i=0; i<13; i++) V[i].clear();
while(n--){
scanf("%s %d %d", s, &i, &j);
k = getnum(s);
V[k].pb((Goods){i,j});
if(k==11 || k==10){//如果发现Weapon和Shield的,也算到Two-Handed里面去
V[12].pb((Goods){i,j});
}
}
//枚举Weapon和Shield两两组合
for(i=0; i<V[11].size(); i++){
for(j=0; j<V[10].size(); j++){
V[12].pb((Goods){V[11][i].dmg+V[10][j].dmg, V[11][i].tou+V[10][j].tou});
}
}
//把存放Shield的清空,用来记录finger的物品,Weapon的清不清空无所谓
V[10].clear();
for(i=0; i<V[9].size(); i++){
V[10].pb(V[9][i]);
//枚举finger物品的两两组合
for(j=i+1; j<V[9].size(); j++){
V[10].pb((Goods){V[9][i].dmg+V[9][j].dmg, V[9][i].tou+V[9][j].tou});
}
}
V[9].clear();//这个清空,因为finger的情况都存到V[10]里面去了
memset(dp,-1,sizeof(dp));
dp[11][0]=0;
for(i=0; i<V[12].size(); i++){
g = V[12][i];
vt = g.tou>m?m:g.tou;
vd = g.dmg;
dp[11][vt] = max(dp[11][vt], vd);
}
for(k=10; k>=0; k--){
for(j=0; j<=m; j++){
dp[k][j] = max(dp[k][j], dp[k+1][j]);
if(dp[k+1][j]==-1)  continue;
for(i=0; i<V[k].size(); i++){
g = V[k][i];
vt = (g.tou+j)>m?m:(g.tou+j);
vd = g.dmg+dp[k+1][j];
dp[k][vt] = max(dp[k][vt], vd);
}
}
}
printf("%d\n", dp[0][m]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: