虚拟理财游戏

一、题目描述

在一款虚拟游戏中生活,你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。

现有一家Bank,它提供有若干理财产品 m 个,风险及投资回报不同,你有 N(元)进行投资,能接收的总风险值为X。

你要在可接受范围内选择最优的投资方式获得最大回报。

备注:

  1. 在虚拟游戏中,每项投资风险值相加为总风险值;
  2. 在虚拟游戏中,最多只能投资2个理财产品;
  3. 在虚拟游戏中,最小单位为整数,不能拆分为小数;
  4. 投资额*回报率=投资回报

二、输入输出描述

输入描述

  • 第一行:3 个整数,依次为产品数 m(1≤m≤20)、总投资额 N(1≤N≤10000)、可接受总风险 X(1≤X≤200);
  • 第二行:m 个整数,为每个产品的投资回报率(1≤回报率≤60);
  • 第三行:m 个整数,为每个产品的风险值(1≤风险值≤100);
  • 第四行:m 个整数,为每个产品的最大投资额度(1≤最大额度≤10000)。

输出描述

  • m 个整数,为每个产品的投资额(未投资则为 0),按产品顺序输出。

三、示例

|----|---------------------------------------------------|
| 输入 | 5 100 10 10 20 30 40 50 3 4 5 6 10 20 30 20 40 30 |
| 输出 | 0 30 0 40 0 |
| 说明 | 投资第二项30个单位,第四项40个单位,总的投资风险为两项相加为4+6=10 |

四、解题思路

  1. 核心思想

在 "仅考虑单项目 / 双项目投资" 的简化场景下,通过枚举所有合法投资组合(单 / 双项目),按 "回报率优先级分配投资额",筛选出 "风险达标且回报最大" 的方案 ------ 核心是 "简化问题维度(仅单 / 双项目)+ 贪心分配投资额 + 枚举找最优"。

  1. 问题本质分析
  • 表层问题:多约束下的投资组合优化(约束:总投资≤N、总风险≤X、单项目投资≤最大可投;目标:回报最大);
  • 深层简化:代码未考虑 3 个及以上项目的组合,仅聚焦单 / 双项目(降低问题复杂度,适合小规模项目场景);
  • 核心矛盾:"风险约束" 与 "回报最大化" 的平衡,通过 "优先投高回报率项目" 的贪心策略解决投资额分配问题。
  1. 核心逻辑
  • 范围限定:仅枚举单项目、双项目组合(避免高维组合的复杂计算);
  • 风险筛选:仅处理 "单项目风险≤X" 或 "双项目总风险≤X" 的组合(满足核心约束);
  • 贪心分配:对合法组合,按回报率高低优先分配投资额(最大化单单位投资的回报);
  • 最优更新:遍历所有合法组合,记录回报最大的投资方案。
  1. 步骤拆解

  2. 输入解析与初始化

    • 读取项目数、总投资、风险容忍度,以及每个项目的回报率、风险、最大可投;
    • 初始化最大回报maxReturn=0,最佳投资方案数组bestInvestments(全 0)。
  3. 单项目投资枚举

    • 遍历每个项目,筛选 "风险≤X" 的项目;
    • 计算该项目的最大可投资额(总投资与项目最大可投的最小值);
    • 计算回报,若大于当前最大回报,更新最大回报和投资方案。
  4. 双项目组合投资枚举

    • 遍历所有i<j的项目组合,筛选 "总风险≤X" 的组合;
    • 按回报率优先级分配投资额(高回报率项目优先投满,剩余资金投低回报率项目);
    • 计算组合回报,若大于当前最大回报,更新最大回报和投资方案。
  5. 结果输出

    • 将最佳投资方案数组按空格拼接,输出最终投资额分配。

五、代码实现

java 复制代码
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringJoiner;

public class Main {
    public static void main(String[] args) {
        // 创建Scanner对象用于获取用户输入
        Scanner sc = new Scanner(System.in);
        // 读取一行输入并将其分割为字符串数组,然后转换为整数数组
        int[] tmp = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        // 获取投资项目数量m、总投资额N和风险容忍度X
        int m = tmp[0];
        int N = tmp[1];
        int X = tmp[2];
        // 读取每个项目的预期回报率
        int[] returns = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        // 读取每个项目的风险值
        int[] risks = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        // 读取每个项目的最大投资额
        int[] maxInvestments = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();

        // 初始化最大回报为0
        int maxReturn = 0;
        // 初始化最大回报对应的投资方案数组
        int[] bestInvestments = new int[m];

        // 遍历所有项目
        for (int i = 0; i < m; i++) {
            // 如果单个项目的风险在容忍度范围内
            if (risks[i] <= X) {
                // 计算对项目i的投资额,不超过总投资额N和项目i的最大投资额
                int investmentForI = Math.min(N, maxInvestments[i]);
                // 计算当前回报
                int currentReturn = investmentForI * returns[i];
                // 如果当前回报大于已知的最大回报
                if (currentReturn > maxReturn) {
                    // 更新最大回报
                    maxReturn = currentReturn;
                    // 重置最佳投资方案数组,并为项目i分配投资额
                    bestInvestments = new int[m];
                    bestInvestments[i] = investmentForI;
                }
            }

            // 遍历项目i之后的项目,寻找两个项目的组合投资方案
            for (int j = i + 1; j < m; j++) {
                // 如果两个项目的风险总和在容忍度范围内
                if (risks[i] + risks[j] <= X) {
                    int investmentForI, investmentForJ;
                    // 根据预期回报率决定投资额分配
                    if (returns[i] > returns[j]) {
                        // 如果项目i的回报率高于项目j,优先投资项目i
                        investmentForI = Math.min(N, maxInvestments[i]);
                        investmentForJ = Math.min(N - investmentForI, maxInvestments[j]);
                    } else {
                        // 如果项目j的回报率高于项目i,优先投资项目j
                        investmentForJ = Math.min(N, maxInvestments[j]);
                        investmentForI = Math.min(N - investmentForJ, maxInvestments[i]);
                    }
                    // 计算当前两个项目组合的回报
                    int currentReturn = investmentForI * returns[i] + investmentForJ * returns[j];
                    // 如果当前回报大于已知的最大回报
                    if (currentReturn > maxReturn) {
                        // 更新最大回报
                        maxReturn = currentReturn;
                        // 重置最佳投资方案数组,并为两个项目分配投资额
                        bestInvestments = new int[m];
                        bestInvestments[i] = investmentForI;
                        bestInvestments[j] = investmentForJ;
                    }
                }
            }
        }

        // 创建StringJoiner对象,用于构建输出格式
        StringJoiner sj = new StringJoiner(" ");
        // 遍历最佳投资方案数组,将投资额添加到StringJoiner中
        for (int investment : bestInvestments) {
            sj.add(String.valueOf(investment));
        }

        // 输出最佳投资方案
        System.out.println(sj.toString());
        // 关闭Scanner对象
        sc.close();
    }
}
相关推荐
User_芊芊君子7 小时前
【LeetCode经典题解】:从前序和中序遍历构建二叉树详解
算法·leetcode·职场和发展
jifengzhiling7 小时前
卡尔曼增益:动态权重,最优估计
人工智能·算法·机器学习
武子康7 小时前
Java-197 消息队列应用场景:缓存预热+限流排队+Redis Lua 扣库存+MQ 削峰填谷
java·redis·缓存·性能优化·消息队列·rabbitmq·java-rabbitmq
全靠bug跑7 小时前
Spring Cloud Gateway 实战:统一鉴权与用户信息全链路透传
java·开发语言·gateway·拦截器
述清-架构师之路8 小时前
【亲测可用】idea设置mvn默认版本路径,setting路径,仓库路径
java·ide·intellij-idea
ULTRA??9 小时前
插入排序算法实现(二分查找搜索版本)
c++·算法
Elias不吃糖9 小时前
LeetCode 71:简化 Unix 路径(Simplify Path)——栈 / vector
算法·leetcode·
sheeta19989 小时前
LeetCode 每日一题笔记 日期:2025.12.15 题目:2110.股票平滑下跌阶段的数目
笔记·算法·leetcode
泡泡以安10 小时前
【Android逆向工程】第3章:Java 字节码与 Smali 语法基础
android·java·安卓逆向