#P3031. 虚拟理财游戏(100分)
-
1000ms
Tried: 255
Accepted: 56
Difficulty: 2
所属公司 :
华为od
-
算法标签>暴力枚举
虚拟理财游戏(100分)
思路:枚举
一开始看题目还以为是一道二维背包DP,但是题目加了一个限制条件:最多只能投资两个理财产品,那么要么就是投资一个,要么就是投资两个,就分别枚举这两种情况,更新最大回报即可。
Python 代码
from itertools import combinations
def main():
# 读取第一行输入:产品数 m,总投资 N,可接受风险 X
m, N, X = map(int, input().split())
# 读取第二行输入:各产品的回报率
return_rates = list(map(int, input().split()))
# 读取第三行输入:各产品的风险值
risk_values = list(map(int, input().split()))
# 读取第四行输入:各产品的最大投资额度
max_investments = list(map(int, input().split()))
# 初始化最大回报值和最佳投资分配方案
max_return = 0
best_allocation = [0]*m
# 枚举所有可能的1个和2个产品组合
for r in range(1,3):
for combo in combinations(range(m), r):
# 计算当前组合的总风险值
total_risk = sum(risk_values[i] for i in combo)
if total_risk > X:
continue # 超出可接受风险,跳过此组合
remaining = N # 剩余的投资额度
allocation = [0]*m # 当前组合的投资分配
# 按回报率降序排序组合中的产品,优先投资回报率高的产品
sorted_combo = sorted(combo, key=lambda x: return_rates[x], reverse=True)
total = 0 # 当前组合的总回报
for i in sorted_combo:
invest = min(max_investments[i], remaining) # 可投资的最大额度
allocation[i] = invest
total += invest * return_rates[i] # 计算回报
remaining -= invest # 更新剩余投资额度
# 更新最大回报和最佳投资分配方案
if total > max_return:
max_return = total
best_allocation = allocation.copy()
# 输出最佳投资分配方案
print(' '.join(map(str, best_allocation)))
if __name__ == "__main__":
main()
Java 代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取第一行输入:产品数 m,总投资 N,可接受风险 X
int m = scanner.nextInt();
int N = scanner.nextInt();
int X = scanner.nextInt();
// 读取第二行输入:各产品的回报率
int[] returnRates = new int[m];
for(int i = 0; i < m; i++) {
returnRates[i] = scanner.nextInt();
}
// 读取第三行输入:各产品的风险值
int[] riskValues = new int[m];
for(int i = 0; i < m; i++) {
riskValues[i] = scanner.nextInt();
}
// 读取第四行输入:各产品的最大投资额度
int[] maxInvestments = new int[m];
for(int i = 0; i < m; i++) {
maxInvestments[i] = scanner.nextInt();
}
scanner.close();
// 初始化最大回报值和最佳投资分配方案
long maxReturn = 0;
long[] bestAllocation = new long[m];
// 枚举所有可能的1个产品组合
for(int i = 0; i < m; i++) {
// 计算当前产品的总风险值
int totalRisk = riskValues[i];
if(totalRisk > X) continue; // 超出可接受风险,跳过
int invest = Math.min(maxInvestments[i], N); // 可投资额度
long total = (long) invest * returnRates[i]; // 计算回报
if(total > maxReturn) {
maxReturn = total;
Arrays.fill(bestAllocation, 0);
bestAllocation[i] = invest;
}
}
// 枚举所有可能的2个产品组合
for(int i = 0; i < m; i++) {
for(int j = i+1; j < m; j++) {
// 计算组合的总风险值
int totalRisk = riskValues[i] + riskValues[j];
if(totalRisk > X) continue; // 超出可接受风险,跳过
// 按回报率降序排序
int first = i, second = j;
if(returnRates[j] > returnRates[i]) {
first = j;
second = i;
}
// 分配投资额度
int investFirst = Math.min(maxInvestments[first], N);
int remaining = N - investFirst;
int investSecond = Math.min(maxInvestments[second], remaining);
// 计算总回报
long total = (long) investFirst * returnRates[first] + (long) investSecond * returnRates[second];
// 更新最大回报和最佳投资分配方案
if(total > maxReturn) {
maxReturn = total;
Arrays.fill(bestAllocation, 0);
bestAllocation[first] = investFirst;
bestAllocation[second] = investSecond;
}
}
}
// 输出最佳投资分配方案
StringBuilder sb = new StringBuilder();
for(int i = 0; i < m; i++) {
sb.append(bestAllocation[i]).append(" ");
}
System.out.println(sb.toString().trim());
}
}
JavaScript 代码
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let inputLines = [];
rl.on('line', (line) => {
if (line.trim() !== '') {
inputLines.push(line.trim());
}
}).on('close', () => {
// 读取第一行输入:产品数 m,总投资 N,可接受风险 X
let [m, N, X] = inputLines[0].split(' ').map(Number);
// 读取第二行输入:各产品的回报率
let returnRates = inputLines[1].split(' ').map(Number);
// 读取第三行输入:各产品的风险值
let riskValues = inputLines[2].split(' ').map(Number);
// 读取第四行输入:各产品的最大投资额度
let maxInvestments = inputLines[3].split(' ').map(Number);
// 初始化最大回报值和最佳投资分配方案
let maxReturn = -1;
let bestAllocation = Array(m).fill(0);
// 枚举所有可能的1个产品组合
for(let i = 0; i < m; i++) {
let totalRisk = riskValues[i];
if(totalRisk > X) continue; // 超出可接受风险,跳过
let invest = Math.min(maxInvestments[i], N);
let total = invest * returnRates[i];
if(total > maxReturn) {
maxReturn = total;
bestAllocation = Array(m).fill(0);
bestAllocation[i] = invest;
}
}
// 枚举所有可能的2个产品组合
for(let i = 0; i < m; i++) {
for(let j = i+1; j < m; j++) {
let totalRisk = riskValues[i] + riskValues[j];
if(totalRisk > X) continue; // 超出可接受风险,跳过
// 按回报率降序排序
let first = i, second = j;
if(returnRates[j] > returnRates[i]) {
first = j;
second = i;
}
// 分配投资额度
let investFirst = Math.min(maxInvestments[first], N);
let remaining = N - investFirst;
let investSecond = Math.min(maxInvestments[second], remaining);
// 计算总回报
let total = investFirst * returnRates[first] + investSecond * returnRates[second];
// 更新最大回报和最佳投资分配方案
if(total > maxReturn) {
maxReturn = total;
bestAllocation = Array(m).fill(0);
bestAllocation[first] = investFirst;
bestAllocation[second] = investSecond;
}
}
}
// 输出最佳投资分配方案
console.log(bestAllocation.join(' '));
});
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// 读取第一行输入:产品数 m,总投资 N,可接受风险 X
int m, N, X;
cin >> m >> N >> X;
// 读取第二行输入:各产品的回报率
vector<int> returnRates(m);
for(auto &x : returnRates) cin >> x;
// 读取第三行输入:各产品的风险值
vector<int> riskValues(m);
for(auto &x : riskValues) cin >> x;
// 读取第四行输入:各产品的最大投资额度
vector<int> maxInvestments(m);
for(auto &x : maxInvestments) cin >> x;
// 初始化最大回报值和最佳投资分配方案
long long maxReturn = -1;
vector<long long> bestAllocation(m, 0);
// 枚举所有可能的1个产品组合
for(int i = 0; i < m; i++) {
int totalRisk = riskValues[i];
if(totalRisk > X) continue; // 超出可接受风险,跳过
int invest = min(maxInvestments[i], N);
long long total = (long long)invest * returnRates[i];
if(total > maxReturn) {
maxReturn = total;
fill(bestAllocation.begin(), bestAllocation.end(), 0LL);
bestAllocation[i] = invest;
}
}
// 枚举所有可能的2个产品组合
for(int i = 0; i < m; i++) {
for(int j = i+1; j < m; j++) {
int totalRisk = riskValues[i] + riskValues[j];
if(totalRisk > X) continue; // 超出可接受风险,跳过
// 按回报率降序排序
int first = i, second = j;
if(returnRates[j] > returnRates[i]) {
first = j;
second = i;
}
// 分配投资额度
int investFirst = min(maxInvestments[first], N);
int remaining = N - investFirst;
int investSecond = min(maxInvestments[second], remaining);
// 计算总回报
long long total = (long long)investFirst * returnRates[first] + (long long)investSecond * returnRates[second];
// 更新最大回报和最佳投资分配方案
if(total > maxReturn) {
maxReturn = total;
fill(bestAllocation.begin(), bestAllocation.end(), 0LL);
bestAllocation[first] = investFirst;
bestAllocation[second] = investSecond;
}
}
}
// 输出最佳投资分配方案
for(int i = 0; i < m; i++) {
cout << bestAllocation[i] << (i < m-1 ? ' ' : '\n');
}
return 0;
}
题目描述
在一款虚拟游戏中生活,你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。现有一家 Bank,它提供有若干理财产品 m 个,风险及投资回报不同,你有 N(元)进行投资,能接收的总风险值为 X。你要在可接受范围内选择最优的投资方式获得最大回报。
备注:
- 在虚拟游戏中,每项投资风险值相加为总风险值;
- 在虚拟游戏中,最多只能投资 2 个理财产品;
- 在虚拟游戏中,最小单位为整数,不能拆分为小数;
- 投资额*回报率=投资回报
输入描述
第一行:
产品数(取值范围[1,20])
总投资数(整数,取值范围[1,10000])
可接受风险值序列(整数,取值范围[1,200])
第二行:产品投资回报率序列,输入为整数,取值范围[1,60]
第三行:产品风险值序列,输入为整数,取值范围[1,100]
第四行:最大投资额度序列,输入为整数,取值范围[1,10000]
输出描述
每个产品的投资序列
样例1
输入
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。