题目
Description
招商银行遇到一位很奇怪的顾客。这位顾客起初用一些人民兑换了另一种货币,然后不断地用一种货币兑换另一种货币,最后又换回人民币。令人惊奇的是,最后换回的人民币居然比他最初带来的多了一些。
例如这样一个兑换过程:
假设1单位人民币兑换6.89单位火星币,1单位火星币兑换0.18单位水星币,1单位水星币兑换0.81单位人民币。
我们用1.20单位人民兑换得8.27单位火星币,然后用这8.27单位火星币兑换得1.49单位水星币,最后用1.49单位水星币兑换到1.21单位人民币。
奇迹就这样发生了。聪明的你一定已经发现了,这都是四舍五入的功劳。
当然这种事情在现实中是不可能的,但我们还是来研究一下这个问题。
假设共有n种货币,编号从1到n。我们最初持有m单位的货币1。已知各种货币之间兑换比率,每次兑换后都四舍五入到小数点后两位。请问兑换k次且换回到货币1后,最多能让我们持有的货币增加多少单位?Input
输入包含多组数据。 每组数据第一行包含两个整数:n (1≤n≤100), k (0≤k≤100),第二行为一个实数m (0ij单位的货币j,注意,不一定能反向兑换。若aij=0,则表示不能直接用货币i兑换货币j。显然不能用货币i换货币i,这样没有意义。 输入以n=k=0结束。
Output
对每组数据输出我们持有的货币1最多能增值多少,精确到小数点后两位。如果不可能增值,则输出”0.00”
Sample Input
3 3
1.20
0.00 6.89 0.00
0.00 0.00 0.18
0.81 0.00 0.00
1 0
1.00
0.00
0 0Sample Output
0.01
0.00
题解
与其说是动态规划,不如说这道题是 贪心+模拟
用计算器跟着样例走一遍就能明白题意
dp[i][j]
表示兑换 j
次且此时为货币 i
的最大钱数
因此初始时为 dp[1][0]
最后结果为 dp[1][k]
每次状态转移为 dp[i][j] = max{ dp[t][j] } (1<=t<=n)
根据转移方程应该先遍历 j
再遍历 i
时间复杂度为 O(n3)
最后要注意如果不能赚钱要输出 0.00
代码
/* By:OhYee Github:OhYee Blog:http://www.oyohyee.com/ Email:oyohyee@oyohyee.com かしこいかわいい? エリーチカ! 要写出来Хорошо的代码哦~ */ #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> using namespace std; const int maxn = 105; const int maxk = 105; double hl[maxn][maxn]; double dp[maxn][maxk]; inline double standard(double a) { return (double)((int)(a * 100 + 0.5)) / 100; } bool Do() { int n,k; scanf("%d%d",&n,&k); if(n == 0 && k == 0) return false; scanf("%lf",&dp[1][0]); for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) scanf("%lf",&hl[i][j]); for(int j = 1;j <= k;j++) for(int i = 1;i <= n;i++) { dp[i][j] = 0; for(int t = 1;t <= n;t++) { dp[i][j] = max(standard(dp[t][j - 1] * hl[t][i]),dp[i][j]); } } if(dp[1][k] - dp[1][0] < 0.0) printf("0.00\n"); else printf("%.2f\n",dp[1][k] - dp[1][0]); return true; } int main() { while(Do()); return 0; }