P1968 [CHCI 2001 Regional Competition Seniors] 美元汇率

记录88

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
double dp[110][2],a[110];
int main(){//两种最大的状态,美元,马克
	int n;
	cin>>n;
	dp[0][0]=100;//初始时候的美元数
	dp[0][1]=0;//初始时候的马克数
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dp[i][0]=max(dp[i-1][0],dp[i-1][1]*(100.0/a[i]));//除一个数,就是乘它的倒数
		dp[i][1]=max(dp[i-1][1],dp[i-1][0]*(a[i]/100.0));
	}
	cout<<fixed<<setprecision(2)<<dp[n][0];
	//printf("%.2f",dp[n][0]);
	return 0;
} 

题目传送门https://www.luogu.com.cn/problem/P1968


突破口

在以后的若干天里戴维将学习美元与德国马克的汇率。编写程序帮助戴维何时应买或卖马克或美元,使他从 100 美元开始,最后能获得最高可能的价值。


思路

🎯 问题本质

  • 戴维初始有 100 美元
  • 接下来 N 天,每天有一个汇率 A_i
    • 100 美元 ⇄ A_i 马克
    • 即:1 美元 = A_i / 100 马克,1 马克 = 100 / A_i 美元
  • 每天他可以选择:
    • 把所有美元换成马克
    • 把所有马克换成美元
    • 什么都不做
  • 目标 :在第 N 天结束前,必须持有美元,且金额最大

💡 关键约束:最后必须是美元

这是一个典型的 动态规划(DP) 问题,状态只有两种:持有美元持有马克


🧠 动态规划设计

状态定义
  • dp[i][0]:第 i 天结束后,持有美元的最大金额
  • dp[i][1]:第 i 天结束后,持有马克的最大金额
初始状态
  • dp[0][0] = 100(开始有 100 美元)
  • dp[0][1] = 0(没有马克)
状态转移(第 i 天)
  • 美元状态 dp[i][0] 可以来自:

    1. 昨天就持有美元,今天不动 → dp[i-1][0]
    2. 昨天持有马克,今天全部换成美元 → dp[i-1][1] × (100 / a[i])
    • 取两者最大值
  • 马克状态 dp[i][1] 可以来自:

    1. 昨天就持有马克,今天不动 → dp[i-1][1]
    2. 昨天持有美元,今天全部换成马克 → dp[i-1][0] × (a[i] / 100)
    • 取两者最大值

✅ 注意:每天最多操作一次(全换或不换),因为部分换不会更优(汇率固定,全换收益最大)

最终答案
  • dp[N][0](第 N 天必须是美元)

代码分析

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
double dp[110][2], a[110];
  • dp[i][0/1]:第 i 天的美元/马克最大值
  • a[i]:第 i 天的汇率(100 美元 ↔ ai 马克)
  • 数组大小 110(因 N ≤ 100)
cpp 复制代码
int main(){
    int n;
    cin >> n;
cpp 复制代码
    dp[0][0] = 100; // 初始 100 美元
    dp[0][1] = 0;   // 初始 0 马克

🔁 每天更新状态

cpp 复制代码
    for(int i = 1; i <= n; i++){
        cin >> a[i];
  • 读入第 i 天的汇率 a[i]
cpp 复制代码
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] * (100.0 / a[i]));
  • 计算第 i 天持有美元的最大值:
    • 不换:dp[i-1][0]
    • 用马克换:dp[i-1][1] 马克 × (100 / a[i]) 美元/马克
cpp 复制代码
        dp[i][1] = max(dp[i-1][1], dp[i-1][0] * (a[i] / 100.0));
  • 计算第 i 天持有马克的最大值:
    • 不换:dp[i-1][1]
    • 用美元换:dp[i-1][0] 美元 × (a[i] / 100) 马克/美元

💡 使用 100.0 而不是 100 是为了强制浮点运算,避免整数除法


🔚 输出结果

cpp 复制代码
    cout << fixed << setprecision(2) << dp[n][0];
    return 0;
}
  • 输出第 n 天的美元金额,保留两位小数
  • fixed + setprecision(2) 确保格式为 xxx.xx

⚠️ 题目允许 ±0.05 误差,所以浮点精度足够


🧪 样例验证(n=5,汇率=400,300,500,300,250

汇率 A dpi0(美元) dpi1(马克) 操作
0 --- 100.00 0.00 初始
1 400 max(100, 0) = 100 max(0, 100×4) = 400 换成马克
2 300 max(100, 400×100/300 ≈133.33) = 133.33 max(400, 100×3=300) = 400 马克换美元
3 500 max(133.33, 400×0.2=80) = 133.33 max(400, 133.33×5≈666.67) = 666.67 美元换马克
4 300 max(133.33, 666.67×100/300≈222.22) = 222.22 max(666.67, 133.33×3=400) = 666.67 ---
5 250 max(222.22, 666.67×100/250=266.67) = 266.67 ... 马克换美元

→ 输出 266.67


总结

要点 说明
状态设计 dp[i][0](美元),dp[i][1](马克)
转移逻辑 每天可选择"换"或"不换",取最大值
汇率转换 100 美元 ↔ A 马克 → 1 美元 = A/100 马克
最终要求 第 N 天必须是美元 → 输出 dp[N][0]
精度处理 double + setprecision(2)

这段代码正确建模了货币兑换的最优决策过程,是动态规划在金融场景中的经典应用。

相关推荐
JieE21210 小时前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE21211 小时前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术15 小时前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦16 小时前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
clint45618 小时前
C++进阶(1)——前景提要
c++
用户4978630507319 小时前
(一)小红的数组操作
算法·编程语言
夜悊1 天前
C++代码示例:进制数简单生成工具
c++
怕浪猫1 天前
Electron 系列文章封面图
算法·架构·前端框架
郝学胜_神的一滴1 天前
CMake 021: IF 条件判据详诠
c++·cmake