【背包dp】输出方案路径

1 01背包输出方案

2 按字典序顺序输出所选背包物品

举个例子,输入的数据↓

bash 复制代码
N=5, V=5
1: v=2 w=3
2: v=1 w=0
3: v=1 w=0
4: v=2 w=3
5: v=1 w=5

按照逆向dp,构造出的dp数组(dpij表示体积为j时,放第i件物品的最大价值)。如下表所示,dp1V存储了n件物品,体积为V时的最大价值。搜索时,正序遍历dp数组,内层循环逆序遍历体积,如果dpi+1curV - v\[i] + wi == dpicurV),说明第i件物品有选。

体积/物品 0 1 2 3 4 5
物品1 0 5 5 8 8 11
物品2 0 5 5 8 8 8
物品3 0 5 5 8 8 8
物品4 0 5 5 8 8 8
物品5 0 5 5 5 5 5
参考代码
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int n, V;
int v[1005], w[1005];
int dp[1005][1005]; // dp[i][j]: 从 i 到 n,容量 j 的最大价值
bool chosen[1005];

int main(){
    cin >> n >> V;
    for(int i = 1; i <= n; i++){
        cin >> v[i] >> w[i];
    }

    // 逆序 DP
    for(int i = n; i >= 1; i--){
        for(int j = 0; j <= V; j++){
            dp[i][j] = dp[i+1][j];
            if(j >= v[i]){
                dp[i][j] = max(dp[i][j], dp[i+1][j - v[i]] + w[i]);
            }
        }
    }

    // 从前往后贪心,保证字典序最小
    int curV = V;
    for(int i = 1; i <= n; i++){
        if(curV >= v[i] && dp[i+1][curV - v[i]] + w[i] == dp[i][curV]){
            chosen[i] = true;
            curV -= v[i];
        }
    }
    for(int i = 1; i <= n; i++){
        if(chosen[i]){
            cout << i<<" ";
        }
    }
    cout << "\n";
    return 0;
}

例题2 洛谷P2066

对于编号小的尽量少分配机器,再做dp时考虑正向。搜索方案的时候逆向搜索。

参考代码
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m, a[20][20], dp[20][20];
int ansk[20];

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> a[i][j];
	for (int i = 1; i <= n; i++) {
		for (int j = m; j >= 1; j--) {
			dp[i][j] = dp[i - 1][j];
			for (int k = 1; k <= j; k++)
				dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + a[i][k]);
		}
	}
	cout << dp[n][m] << endl;
	int curM = m;
	for (int i = n; i >= 1; i--) {
		for (int k = curM; k >= 1; k--) {
			if (dp[i][curM] == dp[i - 1][curM - k] + a[i][k]) {
				ansk[i] = k;
				curM -= k;
				break;
			}
		}
	}
	for (int i = 1; i <= n; i++)
		cout << i << " " << ansk[i] << endl;
	return 0;
}
相关推荐
小成202303202655 小时前
C++~07补充
开发语言·c++
hold?fish:palm6 小时前
40 二叉树的直径
c++·leetcode
解决小子6 小时前
【虚幻引擎】【C++】【GAS框架】构建角色基类、属性集、数值钳制
c++·笔记·游戏引擎·虚幻·gas·能力系统
lunar_coder7 小时前
【C++】如何解决智能指针的析构函数,如何实现shared_ptr的引用计数以及解决shared_ptr的循环引用
c++·1024程序员节
白白白小纯8 小时前
C++进阶.多态
c++
凯瑟琳.奥古斯特9 小时前
力扣1016高效解法:剪枝优化技巧
开发语言·c++·算法·leetcode·职场和发展
xiangyun619 小时前
C++ priority_queue 底层:手撕二叉堆与 Top K 问题
c++·算法·面试·stl·1024程序员节
坤坤子吖9 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
qz_Serene10 小时前
练习算法题:双指针 -cpp
c++·算法·leetcode·1024程序员节
扶尔魔ocy10 小时前
【C++开发】从裸指针到智能指针
c++·智能指针·1024程序员节