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 美元 ↔ a[i] 马克)
  • 数组大小 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 dp[i][0](美元) dp[i][1](马克) 操作
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)

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

相关推荐
Yupureki1 小时前
《Linux系统编程》13.Ext系列文件系统
linux·运维·服务器·c语言·开发语言·c++
liu****1 小时前
4.git远程操作
c++·git·版本控制
博界IT精灵1 小时前
树的概念与性质(哈喜老师)
数据结构
linux开发之路1 小时前
muduo网络库为什么高性能?
c++·网络编程·多线程·epoll·muduo网络库
乐观勇敢坚强的老彭1 小时前
c++图论
开发语言·c++·图论
派大星爱吃鱼1 小时前
侧信道安全(Side-Channel Security)
算法·安全
要努力点1 小时前
26考研——计算机考研复试——0854(2)
java·c语言·考研·算法·复试
梓䈑1 小时前
【CMake】cmake的3大核心:目标、属性 和 API(含大量重点函数解析)
c++·cmake
少许极端1 小时前
算法奇妙屋(三十六)-贪心算法学习之路3
学习·算法·贪心算法·买卖股票问题