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)

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

相关推荐
MC皮蛋侠客2 小时前
Google Test 单元测试指南
c++·单元测试·google test
艾莉丝努力练剑3 小时前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
kkeeper~3 小时前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
2401_868534784 小时前
论企业网络设计
数据结构
wabs6664 小时前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964135 小时前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
basketball6165 小时前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
嗝o゚5 小时前
CANN GE 算子融合——融合算法与调度策略
算法·昇腾·cann·ge
小江的记录本5 小时前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试
Fre丸子_6 小时前
自定义文件夹选取功能
c++