原题: http://acm.hdu.edu.cn/showproblem.php?pid=6508
题意:
有n个卡片,是否为魔法卡,是否可以减费。卡片会消耗w能量,造成x伤寒。每使用一张魔法卡,接下来的可减费的卡消耗-1。初始值为W,问最大伤害。
解析:
用dp[i][j]表示还剩i能量,用了j张魔法的最大伤害。
考虑四种卡片:
- 物理卡不可减费:直接做背包,因为即不会影响别的,又不会被影响。
- 魔法卡不可减费:第二个做,会对接下来两个牌造成影响,但是不受影响。
- 魔法卡可减费:被第二种卡影响,还会影响第四种。
- 物理卡可减费:被第二、三种影响。
其中注意做第三种卡的时候需要按照法力值升序排序。因为有些魔力消耗大的卡可能被小的那些减费,但是直接上的话魔力值不够就变成负数而不考虑这种情况。
做背包的时候要注意状态的枚举是从大到小还是从小到大。如果转移到较大状态则从大到小,反之亦然。(因为是01包)
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod =1e9+7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,b,a) for(int i=b;i>=a;i--)
inline char nc(){
static char buf[1000000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,1000000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
if(c==EOF){
x=-1;
return ;
}
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
int n,W;
int a[4][2][509];
int top[4];
int dp[509][509];
struct node{
int x,w;
bool operator<(const node &R)const{
return w<R.w;
}
}e[509];
int main(){
while(read(n),n!=-1){
memset(dp,0xc0,sizeof dp);
read(W);
dp[W][0]=0;
rep(i,0,3)top[i]=0;
rep(i,1,n){
int w,x,mg,can;
read(w),read(x),read(mg),read(can);
if(!mg&&!can){
a[0][0][++top[0]]=w;
a[0][1][top[0]]=x;
}
else if(mg&&!can){
a[1][0][++top[1]]=w;
a[1][1][top[1]]=x;
}
else if(mg&&can){
a[2][0][++top[2]]=w;
a[2][1][top[2]]=x;
}
else{
a[3][0][++top[3]]=w;
a[3][1][top[3]]=x;
}
}
rep(i,1,top[2]){
e[i].w=a[2][0][i];
e[i].x=a[2][1][i];
}
sort(e+1,e+1+top[2]);
rep(i,1,top[2]){
a[2][0][i]=e[i].w;
a[2][1][i]=e[i].x;
}
rep(i,1,top[0]){
int w=a[0][0][i],x=a[0][1][i];
rep(j,w,W){
if(dp[j][0]>-1e8){
dp[j-w][0]=max(dp[j-w][0],dp[j][0]+x);
}
}
}
rep(i,1,top[1]){
int w=a[1][0][i],x=a[1][1][i];
rep(j,w,W){
repp(k,i-1,0){
if(dp[j][k]>-1e8){
dp[j-w][k+1]=max(dp[j-w][k+1],dp[j][k]+x);
}
}
}
}
rep(i,1,top[2]){
int x=a[2][1][i];
repp(k,i-1+top[1],0){
int w=max(0,a[2][0][i]-k);
rep(j,w,W){
if(dp[j][k]>-1e8){
dp[j-w][k+1]=max(dp[j-w][k+1],dp[j][k]+x);
}
}
}
}
rep(i,1,top[3]){
int x=a[3][1][i];
repp(k,top[2]+top[1],0){
int w=max(0,a[3][0][i]-k);
rep(j,w,W){
if(dp[j][k]>-1e8){
dp[j-w][k]=max(dp[j-w][k],dp[j][k]+x);
}
}
}
}
int ans=-1;
rep(i,0,W){
rep(j,0,top[1]+top[2]){
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
}