Python+Excel脚本实现一键生成动态规划表
导读:刷算法题总被“画DP状态表”折磨?手推容易错,Excel拉公式又容易串列… 今天分享一段不到50行的Python脚本,从Excel读取参数 → 自动跑完二维DP+一维滚动数组快照 → Pandas一键输出高清报表。算法党、数据分析师、面试备考者必藏!
为什么“手动推演DP”是反 人类设计?
动态规划(DP)是算法面试的“重灾区”,但90%的初学者都卡在状态表推演这一步:
- 纸笔手算:格子一多极易串行,回溯最优解直接崩溃
- Excel硬拖:公式嵌套
IF/MAX眼花缭乱,改个参数全盘重算 - 纯写代码:跑完只给个最终答案,中间状态黑盒化,根本不知道“为什么选这个”
破局思路:把“参数配置”交给 Excel,把“状态推演”交给 Python,把“可视化展示”交给 Pandas。数据与逻辑彻底解耦,推演过程透明可追溯!

核心代码拆解:50行搞定DP全自动推演
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
import openpyxl
import pandas as pd
# 1️⃣ 精准读取:从 Excel 剥离业务参数
df_items = pd.read_excel("input_data.xlsx", usecols=[0, 1, 2]).dropna()
df_config = pd.read_excel("input_data.xlsx", usecols=[5, 6]).dropna()
item_names = df_items["物品名称"].tolist()
weights = df_items["物品大小 w[i]"].astype(int).tolist()
values = df_items["物品价值 v[i]"].astype(int).tolist()
max_capacity = int(df_config.loc[df_config["配置项"] == "最大容量 max_capacity", "参数值"].values[0])
# 2️⃣ 二维 DP 推演:完整记录状态转移轨迹
n = len(weights)
dp_2d = [[0] * (max_capacity + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
w, v = weights[i - 1], values[i - 1]
for j in range(max_capacity + 1):
if j < w:
dp_2d[i][j] = dp_2d[i - 1][j]
else:
dp_2d[i][j] = max(dp_2d[i - 1][j], dp_2d[i - 1][j - w] + v)
# 3️⃣ 一维滚动数组 + 历史快照:空间优化 O(C),过程全记录
dp_1d = [0] * (max_capacity + 1)
dp_1d_history = [list(dp_1d)]
for i in range(n):
w, v = weights[i], values[i]
for j in range(max_capacity, w - 1, -1):
dp_1d[j] = max(dp_1d[j], dp_1d[j - w] + v)
dp_1d_history.append(list(dp_1d))
# 4️⃣ Pandas 格式化输出:告别裸 print,表格即报表
columns = [str(j) for j in range(max_capacity + 1)]
index_labels = ["无物品"] + item_names
df_2d = pd.DataFrame(dp_2d, index=index_labels, columns=columns)
df_1d = pd.DataFrame(dp_1d_history, index=index_labels, columns=columns)
print(df_2d.to_string())
print(df_1d.to_string())
为什么这段写法“降维打击”
二维表 vs 一维快照:教学与实战的完美结合
dp_2d:保留完整决策树,适合理解状态转移方程dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + v)dp_1d_history:经典空间优化O(N×C) → O(C),倒序遍历防覆盖。每轮追加list(dp_1d)快照,一眼看清“滚动数组到底怎么滚”,调试/写题解直接截图用。
数据读取“零污染”
df_config.loc[df_config["配置项"] == "最大容量 max_capacity", "参数值"].values[0]
精准定位配置单元格,不依赖固定行号。Excel模板随便挪,Python照样抓得准。
Pandas 一键转报表
index_labels 和 columns 动态生成,索引自带“无物品”占位,列名直接映射容量 0~max_capacity。输出结果可直接 to_excel() 导出,无缝对接汇报材料。
真实业务能怎么用
| 场景 | DP 映射逻辑 | 业务价值 |
|---|---|---|
| 项目预算分配 | 容量=总预算,重量=项目成本,价值=预期收益 | 自动找出 ROI 最高的项目组合 |
| 仓储装载优化 | 容量=货车载重/容积,重量=货物体积,价值=运费/利润 | 单次发车利润最大化 |
| 服务器资源调度 | 容量=CPU/内存上限,重量=任务资源占用,价值=SLA优先级 | 任务排队策略自动推演 |
实战避坑 & 进阶玩法
| 坑点 | 解决方案 |
|---|---|
| Excel含空行/非数字字符 | dropna() + .astype(int) 前置清洗 |
| 想看具体选了哪些物品? | 在二维表基础上加反向回溯逻辑(从 dp[n][C] 逆推) |
| 需要带高亮样式的 Excel 报表? | 代码已导入 openpyxl.styles,可用 worksheet.cell().fill = PatternFill(...) 给最大值加金色背景 |
| 容量/物品数超 1000? | 改用 numpy 数组替代原生 list,内存连续访问提速 5~10 倍 |
结语:算法不是玄学,是工程
很多初学者觉得 DP 抽象,是因为缺乏状态可视化工具。把参数抽离到 Excel,把推演交给 Python,把展示交给 Pandas,你不仅是在写脚本,更是在搭建一套可复用、可审计、可交付的算法引擎。
附完整代码:
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
import openpyxl
import pandas as pd
# ==============================================================================
# 1.输入参数的 Excel 文件 (input_data.xlsx)
# ==============================================================================
# 在这里原始数据表,
input_file = "input_data.xlsx"
# ==============================================================================
# 2. 读取与计算阶段:完全从 Excel 中加载数据,并计算生成最终的 DP 状态表
# ==============================================================================
# ---- A. 从 Excel 中读取数据 ----
df_read_items = pd.read_excel(input_file, usecols=[0, 1, 2]).dropna()
df_read_config = pd.read_excel(input_file, usecols=[5, 6]).dropna()
# 从读取到的 DataFrame 中还原出变量列表
item_names = df_read_items["物品名称"].tolist()
weights = df_read_items["物品大小 w[i]"].astype(int).tolist()
values = df_read_items["物品价值 v[i]"].astype(int).tolist()
# 从配置区精准提取最大容量数字
max_capacity = int(df_read_config.loc[df_read_config["配置项"] == "最大容量 max_capacity", "参数值"].values[0])
# ---- B. 核心动态规划算法核心逻辑 ----
n = len(weights)
# 1. 计算二维 DP 状态表
dp_2d = [[0] * (max_capacity + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
w, v = weights[i - 1], values[i - 1]
for j in range(max_capacity + 1):
if j < w:
dp_2d[i][j] = dp_2d[i - 1][j]
else:
dp_2d[i][j] = max(dp_2d[i - 1][j], dp_2d[i - 1][j - w] + v)
# 2. 计算一维滚动数组并截取每轮的历史快照
dp_1d = [0] * (max_capacity + 1)
dp_1d_history = [list(dp_1d)]
for i in range(n):
w, v = weights[i], values[i]
for j in range(max_capacity, w - 1, -1):
dp_1d[j] = max(dp_1d[j], dp_1d[j - w] + v)
dp_1d_history.append(list(dp_1d))
# ---- C. 使用 Pandas 格式化输出最终内容 ----
columns = [str(j) for j in range(max_capacity + 1)]
index_labels = ["无物品"] + item_names
print("="*43 + " 最终输出 1:二维 DP 状态表 " + "="*43)
df_output_2d = pd.DataFrame(dp_2d, index=index_labels, columns=columns)
df_output_2d.index.name = "物品名称"
print(df_output_2d.to_string())
print("\n" + "="*41 + " 最终输出 2:一维滚动数组快照表 " + "="*41)
df_output_1d = pd.DataFrame(dp_1d_history, index=index_labels, columns=columns)
df_output_1d.index.name = "物品名称"
print(df_output_1d.to_string())
到此这篇关于 Python+Excel脚本实现一键生成动态规划表的文章就介绍到这了,更多相关Python Excel生成动态规划表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


最新评论