VOJ - Did he drop any good loot? (三维DP)

Did he drop any good loot?

题目链接:A - Did he drop any good loot? Gym - 100694A

题意

n种物品,每种物品有价值p[i]、重量w[i]和加成d[i],d[i]表示如果带上i物品则可以额外多带d[i]单位重量,最多能带m单位重量的物品,所带物品最多有两个物品可以加成,问最多可以带多少价值的物品


思路

如果没有那个d[i]的话,就肯定是用dp了,这里就可以用三维DP来模拟了,注意,在拿到加力量的物品之前,可能会出现负重为负的情况,所以这里最后将总容量在加上300,从dp[].[300].[]开始进行计算。

这用记忆话搜索也非常棒,这里用下大神的代码


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)1e6+7;
const int INF = (int)0x3f3f3f3f;

int n,m,now;
int dp[2][1105][3];
int p,w,d;

int main(){
    int f = 0,ans = 0;
    scanf("%d %d",&n,&m);
    mmm(dp,-125);
    dp[f^1][300][0] = 0;
    rep(i,1,n) {
        scanf("%d %d %d",&p,&w,&d);
        mmm(dp[f],-125);
        rep(j,0,1100) {
            if (j-w >= 0){
                dp[f][j][0] = max(dp[f^1][j][0],dp[f^1][j-w][0]+p);
                dp[f][j][1] = max(dp[f^1][j][1],dp[f^1][j-w][1]+p);
                dp[f][j][2] = max(dp[f^1][j][2],dp[f^1][j-w][2]+p);
            }
            if (j-w+d <= 1100 && j-w+d >= 0){
                dp[f][j][1] = max(dp[f][j][1],dp[f^1][j-w+d][0]+p);
                dp[f][j][2] = max(dp[f][j][2],dp[f^1][j-w+d][1]+p);
            }

            if (j <= m+300) ans =  max(ans,max(dp[f][j][0],max(dp[f][j][1],dp[f][j][2])));
        }
        f ^= 1;
    }
    printf("%d\n",ans);
}

记忆化搜索

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x7fffffff
#define maxn 10001
int n,m;
ll p[maxn],w[maxn],d[maxn],dp[10001][901][3];
bool vis[10001][901][3];
ll dfs(int pos,ll pre,int last)
{
    if(pos==n+1)
    {
        if(pre>=200)
            return 0;
        return -INF;
    }
    if(vis[pos][pre][last])
        return dp[pos][pre][last];
    vis[pos][pre][last]=1;
    dp[pos][pre][last]=dfs(pos+1,pre,last);
    if(pre>=w[pos])
        dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre-w[pos],last)+p[pos]);
    if(last&&(pre+d[pos]>=w[pos]))
        dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre+d[pos]-w[pos],last-1)+p[pos]);
    return dp[pos][pre][last];
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; i++)
            scanf("%I64d%I64d%I64d",&p[i],&w[i],&d[i]);
        memset(vis,0,sizeof(vis));
        printf("%I64d\n",dfs(1,m+200,2));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值