背包问题

本文详细解析了背包问题的动态规划解决方案,包括0-1背包、完全背包和多重背包问题,通过实例代码展示了如何求解最大价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:https://www.cnblogs.com/fengziwei/p/7750849.html

背包问题泛指以下这一种问题:

给定一组有固定价值和固定重量的物品,以及一个已知最大承重量的背包,求在不超过背包最大承重量的前提下,能放进背包里面的物品的最大总价值。

这一类问题是典型的使用动态规划解决的问题,我们可以把背包问题分成3种不同的子问题:0-1背包问题、完全背包和多重背包问题。下面对这三种问题分别进行讨论。

1.0-1背包问题

0-1背包问题是指每一种物品都只有一件,可以选择放或者不放。现在假设有n件物品,背包承重为m。

对于这种问题,我们可以采用一个二维数组去解决:f[i][j],其中i代表加入背包的是前i件物品,j表示背包的承重,f[i][j]表示当前状态下能放进背包里面的物品的最大总价值。那么,f[n][m]就是我们的最终结果了。

采用动态规划,必须要知道初始状态和状态转移方程。初始状态很容易就能知道,那么状态转移方程如何求呢?对于一件物品,我们有放进或者不放进背包两种选择:

(1)假如我们放进背包,f[i][j] = f[i - 1][j - weight[i]] + value[i],这里的f[i - 1][j - weight[i]] + value[i]应该这么理解:在没放这件物品之前的状态值加上要放进去这件物品的价值。而对于f[i - 1][j - weight[i]]这部分,i - 1很容易理解,关键是 j - weight[i]这里,我们要明白:要把这件物品放进背包,就得在背包里面预留这一部分空间。

(2)假如我们不放进背包,f[i][j] = f[i - 1][j],这个很容易理解。

因此,我们的状态转移方程就是:f[i][j] = max(f[i][j] = f[i - 1][j] , f[i - 1][j - weight[i]] + value[i])

当然,还有一种特殊的情况,就是背包放不下当前这一件物品,这种情况下f[i][j] = f[i - 1][j]。

下面是实现的代码:

#include <iostream>
#define V 500
using namespace std;
int weight[20 + 1];
int value[20 + 1];
int f[20 + 1][V + 1];
int main() {
    int n, m;
    cout << "请输入物品个数:";
    cin >> n;
    cout << "请分别输入" << n << "个物品的重量和价值:" << endl; 
    for (int i = 1; i <= n; i++) {
        cin >> weight[i] >> value[i];
    }
    cout << "请输入背包容量:";
    cin >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (weight[i] > j) {
                f[i][j] = f[i - 1][j];
            }
            else {
                f[i][j] = f[i - 1][j] > f[i - 1][j - weight[i]] + value[i] ? f[i - 1][j] : f[i - 1][j - weight[i]] + value[i];
            }
        }
    }    
    cout << "背包能放的最大价值为:" << f[n][m] << endl;
}

特别的是,0-1背包问题还有一种更加节省空间的方法,那就是采用一维数组去解决,下面是代码:

#include <iostream>
#define V 500
using namespace std;
int weight[20 + 1];
int value[20 + 1];
int f[V + 1];
int main() {
    int n, m;
    cout << "请输入物品个数:";
    cin >> n;
    cout << "请分别输入" << n << "个物品的重量和价值:" << endl; 
    for (int i = 1; i <= n; i++) {
        cin >> weight[i] >> value[i];
    }
    cout << "请输入背包容量:";
    cin >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= 1; j--) {
            if (weight[i] <= j) {
                f[j] = f[j] > f[j - weight[i]] + value[i] ? f[j] : f[j - weight[i]] + value[i];
            }
        }
    }
    cout << "背包能放的最大价值为:" << f[m] << endl;
}

当我们要求f[j]时,f[j -1]到f[1]还保存着下面一行的状态,因此可以采用一维数组解决。我们可以考虑一下假如不把第二层循环颠倒,当要求f[j]时,f[j - 1]到f[1]已经是同一行的状态了,根本没法求。

2.完全背包问题

完全背包问题是指每种物品都有无限件,具体的解法我也解释不清楚,只能先放代码,谈谈我的理解了:

#include <iostream>
#define V 500
using namespace std;
int weight[20 + 1];
int value[20 + 1];
int f[V + 1];
int max(int a, int b) {
    return a > b ? a : b;
}
int main() {
    int n, m;
    cout << "请输入物品个数:";
    cin >> n;
    cout << "请分别输入" << n << "个物品的重量和价值:" << endl; 
    for (int i = 1; i <= n; i++) {
        cin >> weight[i] >> value[i];
    }
    cout << "请输入背包容量:";
    cin >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = weight[i]; j <= m; j++) {
            f[j] = max(f[j], f[j - weight[i]] + value[i]);
        }
    }
    cout << "背包能放的最大价值为:" << f[m] << endl;
}

i=1时,计算只放第一件物品的最大价值。

i=2时,计算加上第二件物品的最大价值(在只放第一件物品的前提下)

以此类推……

值得注意的是,第二层循环要从j=weight[i]开始,这个稍微理解一下即可。

我在别的博客看到了一段分析0-1背包问题和完全背包问题区别的话,觉得对理解这两个问题很有帮助,因此截图如下:
在这里插入图片描述

3.多重背包问题

多重背包问题限定了一种物品的个数,解决多重背包问题,只需要把它转化为0-1背包问题即可。比如,有2件价值为5,重量为2的同一物品,我们就可以分为物品a和物品b,a和b的价值都为5,重量都为2,但我们把它们视作不同的物品。

代码如下:

#include <iostream>
using namespace std;
#define V 1000
int weight[50 + 1];
int value[50 + 1];
int num[20 + 1];
int f[V + 1];
int max(int a, int b) {
    return a > b ? a : b;
}
int main() {
    int n, m;
    cout << "请输入物品个数:";
    cin >> n;
    cout << "请分别输入" << n << "个物品的重量、价值和数量:" << endl; 
    for (int i = 1; i <= n; i++) {
        cin >> weight[i] >> value[i] >> num[i];
    }
    int k = n + 1;
    for (int i = 1; i <= n; i++) {
        while (num[i] != 1) {
            weight[k] = weight[i];
            value[k] = value[i];
            k++;
            num[i]--;
        }
    }
    cout << "请输入背包容量:";
    cin >> m;
    for (int i = 1; i <= k; i++) {
        for (int j = m; j >= 1; j--) {
            if (weight[i] <= j) f[j] = max(f[j], f[j - weight[i]] + value[i]);
        }
    }
    cout << "背包能放的最大价值为:" << f[m] << endl;
}
### Pandas 文件格式读写操作教程 #### 1. CSV文件的读取与保存 Pandas 提供了 `read_csv` 方法用于从 CSV 文件中加载数据到 DataFrame 中。同样,也可以使用 `to_csv` 将 DataFrame 数据保存为 CSV 文件。 以下是具体的代码示例: ```python import pandas as pd # 读取CSV文件 df = pd.read_csv('file.csv') # 加载本地CSV文件 [^1] # 保存DataFrame为CSV文件 df.to_csv('output.csv', index=False) # 不保存行索引 [^1] ``` --- #### 2. JSON文件的读取与保存 对于JSON格式的数据,Pandas 支持通过 `read_json` 和 `to_json` 进行读取和存储。无论是本地文件还是远程 URL 都支持。 具体实现如下所示: ```python # 读取本地JSON文件 df = pd.read_json('data.json') # 自动解析为DataFrame对象 [^3] # 从URL读取JSON数据 url = 'https://example.com/data.json' df_url = pd.read_json(url) # 直接从网络地址获取数据 # 保存DataFrame为JSON文件 df.to_json('output.json', orient='records') ``` --- #### 3. Excel文件的读取与保存 针对Excel文件操作Pandas 使用 `read_excel` 来读取 `.xls` 或 `.xlsx` 格式的文件,并提供 `to_excel` 方法导出数据至 Excel 表格。 注意:需要安装额外依赖库 `openpyxl` 或 `xlrd` 才能正常运行这些功能。 ```python # 安装必要模块 (如果尚未安装) !pip install openpyxl xlrd # 读取Excel文件 df_excel = pd.read_excel('file.xlsx', sheet_name='Sheet1') # 导出DataFrame为Excel文件 df.to_excel('output.xlsx', sheet_name='Sheet1', index=False) ``` --- #### 4. SQL数据库的交互 当涉及关系型数据库时,Pandas 可借助 SQLAlchemy 库连接各种类型的数据库(如 SQLite, MySQL)。它允许直接查询并将结果作为 DataFrame 返回;或者反过来把现有 DataFrame 插入到指定表中。 下面是基于SQLite的一个例子: ```python from sqlalchemy import create_engine # 创建引擎实例 engine = create_engine('sqlite:///database.db') # 查询SQL语句并返回DataFrame query = "SELECT name, salary, department FROM employees" sql_df = pd.read_sql(query, engine) # 计算各部门平均工资 avg_salary_by_dept = sql_df.groupby('department')['salary'].mean() # 将DataFrame存回SQL表 avg_salary_by_dept.to_sql(name='average_salaries_per_department', con=engine, if_exists='replace', index=True) ``` 上述片段说明了如何执行基本SQL命令以及后续数据分析流程[^4]。 --- #### 5. 多层次索引(MultiIndex)的应用场景 除了常规单维度索引外,在某些复杂情况下可能需要用到多级索引结构。这时可以依靠 MultiIndex 构建更加灵活的数据模型。 例如定义一个多层列名体系: ```python arrays = [['A','A','B','B'], ['foo','bar','foo','bar']] tuples = list(zip(*arrays)) index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second']) df_multi_indexed = pd.DataFrame([[0,1,2,3], [4,5,6,7]], columns=index) print(df_multi_indexed) ``` 这段脚本演示了怎样构建一个具有双重分类标签的表格布局[^2]。 --- ### 总结 综上所述,Pandas 是一种强大而易用的数据处理工具包,适用于多种常见文件类型之间的相互转换及其高级特性应用开发之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值