动态规划(一)

动态规划(一)

  • 1.背包问题
    • 1.1 01背包问题
      • 问题描述
      • 基本思路
      • 优化版思路
    • 1.2 完全背包问题
      • 问题描述
      • 基本思路
      • 优化版思路

1.背包问题

1.1 01背包问题

问题描述

N {N} N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。
i i i 件物品的体积是 v i v_i vi,价值是 w i w_i wi
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数, N , V N,V NV,用空格隔开,分别表示物品数量和背包容积。

接下来有 N N N行,每行两个整数 v i v_i vi, w i w_i wi,用空格隔开,分别表示第 i i i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N , V ≤ 1000 00<N,V1000
0 < v i , w i ≤ 1000 00<vi,wi1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例

8

基本思路

定义记录状态的函数 f [ i ] [ j ] f[i][j] f[i][j],意为:当背包容量为 j j j时,选取前 i i i个物品能获取的最大价值为 f [ i ] [ j ] f[i][j] f[i][j]
f [ i ] [ j ] f[i][j] f[i][j]而言,有2种方式可从前一阶段到达 f [ i ] [ j ] f[i][j] f[i][j]1.将物品 i i i不纳入背包 f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i1][j]
2.物品 i i i纳入背包 f [ i ] [ j ] = f [ i − 1 ] [ j − v [ i ] ] + w [ i ] f[i][j]=f[i-1][j-v[i]]+w[i] f[i][j]=f[i1][jv[i]]+w[i]
//如果纳入背把,则需预留 v [ i ] v[i] v[i]空位,因此剩下 j − v [ i ] j-v[i] jv[i]的空位

代码

#include 
using namespace std;
const int N = 1010;
int f[N][N];
int v[N], w[N];
int n, m;
int main(){
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            f[i][j]=f[i-1][j];
            if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
        }
 
    }
    cout<

优化版思路

从以上基本思路得知,后一状态的 f f f仅与前一状态的有关,因此可优化为一维数组。
j j j v [ i ] v[i] v[i]遍历到 m m m,则 f [ j − v [ i ] ] f[j - v[i]] f[jv[i]]可能取到的是 i i i层状态下的值,而并非 i − 1 i-1 i1层的,为避免这一情况,需将 j j j从后往前遍历。

#include 
using namespace std;
const int N = 1010;
int f[N];
int v[N], w[N];
int n, m;
int main(){
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];

    for(int i=1;i<=n;i++){
        for(int j=m;j>=v[i];j--){
           f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }
    cout<

1.2 完全背包问题

问题描述

N {N} N 件物品和一个容量是 V V V 的背包。每种物品都有无限件可用。
i i i 件物品的体积是 v i v_i vi,价值是 w i w_i wi
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数, N , V N,V NV,用空格隔开,分别表示物品数量和背包容积。

接下来有 N N N行,每行两个整数 v i v_i vi, w i w_i wi,用空格隔开,分别表示第 i i i 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N , V ≤ 1000 00<N,V1000
0 < v i , w i ≤ 1000 00<vi,wi1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例

10

基本思路

与01背包问题相似,不过需遍历物品 i i i 1 , 2 , 3... k , 且 取 到 k 时 不 超 过 背 包 容 量 上 限 1,2,3...k,且取到k时不超过背包容量上限 1,2,3...k,k
代码

#include 
using namespace std;
const int N = 1010;
int f[N][N];
int v[N], w[N];
int n, m;
int main(){
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=0;v[i]*k<=j;k++){
               f[i][j] = max(f[i][j], f[i-1][j - k*v[i]] + k*w[i]);
            }
        }
    }
    cout<

优化版思路

代码

#include 
using namespace std;
const int N = 1010;
int f[N];
int v[N], w[N];
int n, m;
int main(){
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];

    for(int i=1;i<=n;i++){
        for(int j=v[i];j<=m;j++){

               f[j] = max(f[j], f[j - v[i]] + w[i]);
            }
        
    }
    cout<

你可能感兴趣的:(动态规划,算法,数据结构)