( 动态规划专题 )【 补充--记录路径的01背包 】

( 动态规划专题 )【 补充--记录路径的01背包 】

在01背包问题中,求出最优解并记录背包内物品,动态规划的方法求其问题,最核心的公式为f[i][j]=max{f[i-1][j],f[i-1][j-weight[i]]+value[i]},
在考虑当前第i个物品是否放入的时候就是比较
前面的i-1个物品放在容量为j的背包中时背包中总价值与
前面的i-1个物品放在容量为j-weight[i]的背包中并加上当前第i个的价值value[i]的总价值
比较完后选择当前i个物品放在j容量的包中的最佳方案。
同时在记录其路径的时候,路径为conf[i][j]=0或1,若当前f[i][j]为放入第i件物品,则为1,最终形成一个i行j列的矩阵
f形成的矩阵中第N行J列即为前N件物品放在J容量的包中最大价值解。
其路径便从第N行开始输出,路径conf形成的矩阵第N行J列即为第N件物品在包容量为J时是否放入,若N行J列为0,则代表第N件物品未放入J容量的包中,则再看第N-1件物品,若N-1件物品放入了包中即当前位置为1,则需要在包容量J上减去此时的weight[i],如此反复直到物品全部检索完或者容量小于0。

                                                                                                                                           ---------------------------HOXJUN

例题:E - Optimal Slots   Gym - 102219E

Input

该行以两个整数sum和n开头,这两个整数是在特定周末分配给大厅使用的时间以及事件的数量。之后n个整数是事件的持续时间

5 5 1 2 3 4 5
10 9 11 9 3 5 8 4 9 3 2
16 8 12 6 11 11 13 1 10 7
13 5 10 12 2 13 10
28 14 18 19 26 15 18 24 7 21 14 25 2 12 9 6
0

Output

对于每行输入值,首先在一行中输出一个整数列表,这些整数是所选事件持续时间,另一个整数是所选事件持续时间的总和。

1 4 5
3 5 2 10
6 10 16
13 13
19 7 2 28

题意:给定sum,从n个数里挑选任意个数,使得挑选出的数的和小于sum并且最接近sum。输出最优的选择,如果和相等,优先选择更靠前的数。

思路:01背包+记录路径。这里要求选择更靠前的数,所以直接把a数组逆置。

代码:

#include <bits/stdc++.h>

using namespace std;

int a[2005];
int dp[2005];
int path[2005][2005];

int main()
{
	int sum,n;
	while( cin>>sum ) {
        if ( sum==0 ) break;
        cin >> n;
        memset(path,0,sizeof(path));
        for ( int i=n; i>=1; i-- ) scanf("%d",&a[i]);
        memset(dp,0,sizeof(dp));
        for ( int i=1; i<=n; i++ ) {
            for ( int j=sum; j>=0; j-- ) {
                if ( j>=a[i] ) {
                    if ( dp[j] <= dp[j-a[i]]+a[i] ) {
                        dp[j] = dp[j-a[i]]+a[i];
                        path[i][j] = 1;  //若决定放入当前物品,则记为1  
                    }
                }
            }
        }
        for ( int i=n,j=sum; i>0&&j>0; i-- ) { //路径记录
            if ( path[i][j] ) {  //第i件物品是否放入容量剩余j的包中
                cout << a[i] << " ";
                j -= a[i];  //减去当前已经放入的物品占值后的剩余包容量
            }
        }
        cout << dp[sum] << endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值