整股预算下的最大期望收益组合
Budgeted Whole-Share Portfolio
开始编码某基本面策略组本周筛出了 N 个候选股票(每个对应一手已经定好仓位规模的「整手」交易包)。第 i 个资产入场需要的总现金为整数 costs[i] 美元(已包含整手数 × 单股价 × 撮合摩擦),分析师给出的未来一段时间预期美元收益为 expected_returns[i](浮点美元,可正可负——负数代表「分析师不看好这个标的」)。组合经理手上的现金预算是整数 budget 美元,希望从 N 个候选里挑一个子集 —— 每个标的要么完整建仓一手、要么完全跳过(不允许加仓、不允许做空、不允许建半仓)—— 在总成本不超过 budget 的前提下,最大化子集的期望美元收益总和。
请实现 solution(costs: list[int], expected_returns: list[float], budget: int) -> float。规则:(a)costs 与 expected_returns 等长,下标一一对应;(b)每个资产至多被选一次(0/1 决策);(c)所选资产的成本之和必须 ≤ budget;(d)不强制必须把预算花完,也不强制必须建任何仓——若全部跳过,收益是 0.0,所以最终答案永远 ≥ 0.0。
示例:solution([6, 5, 5], [7.0, 5.0, 5.0], 10) 应返回 10.0。三种可行子集:选 {A} 花 6 元、收益 7.0;选 {B, C} 花 10 元、收益 10.0;选 {A, B} 花 11 元 > 10 不可行。最优是 {B, C}。注意「按单位成本收益贪心」会先选 A(A 的 ratio≈1.17 高于 B、C 的 1.0),剩 4 元买不起任何东西,只拿到 7.0——这就是整数预算让贪心失效的地方。再看 solution([3, 4, 5], [-1.0, 2.0, 3.0], 8):资产 0 期望收益为负,DP 不会主动选它;最优是 {1, 2} 共花 9 元……不对,9 > 8,不可行;那退而求其次是 {2} 花 5 元、收益 3.0,或 {1} 花 4 元、收益 2.0,最优 3.0。
朴素地枚举所有 2^N 个子集在 N=200 时是 1.6 × 10⁶⁰ 量级,完全不可行。关键观察是预算是整数且上限只有 10⁴,所以可以建一张「在预算 b 元以内最多能拿多少期望收益」的 DP 表,逐资产做 0/1 背包转移;时间复杂度 O(N · B),在 N=200、B=10⁴ 下是 2×10⁶ 次基本运算,毫秒级完成。这是 0/1 背包在投资组合场景下的标准应用——也是为什么真实的「整手约束 + 整数预算」问题不能用连续凸优化(如 Markowitz)一锤子解决,而要回退到组合优化的原因之一。
约束条件
- 1 ≤ len(costs) = len(expected_returns) ≤ 200
- 0 ≤ costs[i] ≤ 10000(整数美元,单个资产「整手」的总价)
- −10⁴ ≤ expected_returns[i] ≤ 10⁴(浮点美元,可正可负)
- 0 ≤ budget ≤ 10000(整数美元)
- 每个资产**至多买一手**(0/1 背包,不允许加仓也不允许做空)
- 总成本不得超过预算;不强制把预算花完
- 返回值允许 1e-6 的浮点误差
样例
Case 1 · greedy ratio loses to DP
输入: [[6,5,5],[7,5,5],10]
期望: 10
三种可行子集:{A} 花 6 元收益 7.0;{B,C} 花 10 元收益 10.0;{A,B} 共 11 元超预算。最优 {B,C}=10.0。注意按 ratio=ret/cost 贪心会先吃 A(ratio≈1.17 > 1.0),剩 4 元买不起 B 或 C,只能拿 7.0——这正是整数预算让贪心失效的经典反例。
Case 2 · negative-return asset is skipped, tight budget
输入: [[3,4,5],[-1,2,3],8]
期望: 3
资产 0 的期望收益为负,DP 永远不会主动选它。剩下的可行子集:{1}=2.0、{2}=3.0、{1,2} 成本 9 超预算。最优 {2}=3.0。注意「不强制必须选」让 DP 自动忽略亏损项;如果硬要把负收益资产塞进去,反而会拉低总收益。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · greedy ratio loses to DP
输入: [[6,5,5],[7,5,5],10]
期望: 10
三种可行子集:{A} 花 6 元收益 7.0;{B,C} 花 10 元收益 10.0;{A,B} 共 11 元超预算。最优 {B,C}=10.0。注意按 ratio=ret/cost 贪心会先吃 A(ratio≈1.17 > 1.0),剩 4 元买不起 B 或 C,只能拿 7.0——这正是整数预算让贪心失效的经典反例。
Case 2 · negative-return asset is skipped, tight budget
输入: [[3,4,5],[-1,2,3],8]
期望: 3
资产 0 的期望收益为负,DP 永远不会主动选它。剩下的可行子集:{1}=2.0、{2}=3.0、{1,2} 成本 9 超预算。最优 {2}=3.0。注意「不强制必须选」让 DP 自动忽略亏损项;如果硬要把负收益资产塞进去,反而会拉低总收益。