背包与魔法(c++)

目录

问题描述

 问题分析(dp五部曲)

    1.确定状态

           2.递推公式

    3.初始化:

    4.遍历顺序:

    5.画表手推

AC-code

问题描述

 问题分析(dp五部曲)

    1.确定状态

  dp[i][j][0]、dp[i][j][1]分别表示未使用魔法和使用了魔法的情况下容量为j的包装0-i的物品的最大价值。

       
    2.递推公式

    ·对于dp[i][j][0]:
            dp[i][j][0] = j>=w[i] ? max(dp[i-1][j][0], dp[i-1][j-w[i]][0]+v[i]) : dp[i-1][j][0]
        对于dp[i][j][1]:
        使用了魔法的状态,可能是之前使用,也可能是当前这次使用
        1)如果是之前使用了 dp[i][j][1] = j<w[i] ? dp[i-1][j][1] : max(dp[i-1][j][1],dp[i-1][j-w[i]][1]+v[i])
        2)如果是此次使用  if(j>=w[i]+k) dp[i][j][1] = dp[i-1][j-w[i]-k][0] + 2*v[i]
        取最大即可

    3.初始化:

        dp[0][i][0] = j>=w[0] ? v[0] : 0;
        dp[0][i][1] = j>=w[0]+k ? 2*v[0] : 0;

    4.遍历顺序:

        for i in range(n):
            for j in range(m+1):
                for k in range(2):

    5.画表手推

            对于示例数据:

                n=3 m=10 g=3
                 5 10         4 9         3 8

            k == 0    j 0  1  2  3  4  5  6  7  8  9  10
            5 10    i 0 0  0  0  0  0  10 10 10 10 10 10
            4 9        1 0  0  0  0  9  10 10 10 10 19 19
            3 8        2 0  0  0  8  9  10 10 17 18 19 19

            k == 1    j 0  1  2  3  4  5  6  7  8  9  10
            5 10    i 0 0  0  0  0  0  0  0  0  20 20 20
            4 9        1 0  0  0  0  9  9  9 18 20 20 20
            3 8        2 0  0  0  8  9 9 16 18 20 20 26

AC-code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e3+5, maxm=1e4+5;
int w[maxn],v[maxn],n,m,k;
int dp[maxn][maxm][2];
int main()
{
  cin >> n >>m >>k;
  for(int i=0; i<n; i++)  scanf("%d%d",&w[i],&v[i]);
  for(int i=0; i<=m; i++)
	{
		dp[0][i][0] = i>=w[0] ? v[0] : 0;
		dp[0][i][1] = i>=w[0]+k ? 2*v[0] : 0;
	}
	for(int i=1; i<n; i++)
		for(int j=1; j<=m; j++)
		{
			if(j>=w[i]+k)
			{
				dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j-w[i]][0]+v[i]);
				int v1 = dp[i-1][j-w[i]-k][0] + 2*v[i], v2 = dp[i-1][j-w[i]][1]+v[i], v3 = dp[i-1][j][1];
	  		dp[i][j][1] = max(v1,max(v2,v3));
			}
			else if(j>=w[i])
			{
				dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j-w[i]][0]+v[i]);
				dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j-w[i]][1]+v[i]);
			}
			else
			{
				dp[i][j][0] = dp[i-1][j][0];
				dp[i][j][1] = dp[i-1][j][1];
			}
		}
	cout << max(dp[n-1][m][0],dp[n-1][m][1]);
  return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值