UVa 104|Arbitrage|Floyd

原文地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=40

题目翻译

套汇是对一种货币进行的交易,希望通过发现货币间汇率的细小差别获利。比如,如果1美元可以购买0.7英镑,1英镑可以购买9.5法郎,1法郎可以购买0.16美元。那么1美元通过这样的兑换路径可以兑换到 1×0.7×9.5×0.16=1.064 美元,赚了 6.4

你现在需要写个程序找到是否存在这样一个符合上述的兑换序列。
一次成功的套汇必须是从某种货币开始,最后兑换回这个货币。但是某种货币随意选择。

输入

输入文件包含多组数据,每组数据第一行一个整数n( 2nleq20 ),表示兑换表格的尺寸。
接下来n行,每行n-1个整数,表示兑换表格(表格中自己兑换自己的项省略,因为必为1.0),第i行表示1个单位的第i种货币能兑换其他货币多少钱。

输出

对于每个测试数据,你必须决定是否存在一个兑换序列,使得1个单位的某种货币兑换回本币后超过1.01个单位。如果存在,你必须输出这个兑换序列。如果存在多种兑换序列,输出最短的那个。

因为美国国税局注意到了冗长的兑换序列,所以规定一个获益的兑换序列中货币兑换次数不能多过n次。比如序列 1 2 1的兑换次数为2次。

如果存在一个有收益的兑换序列,你必须输出它。序列由货币的编号组成,输出时用空格隔开。序列的第一个元素和最后一个元素必须相同,为兑换的本币。

如果这样的兑换序列不存在,输出一行”no arbitrage sequence exists”(不包括引号)。

样例输入

3
1.2 .89
.88 5.1
1.1 0.15
4
3.1 0.0023 0.35
0.21 0.00353 8.13
200 180.559 10.339
2.11 0.089 0.06111
2
2.0
0.45

样例输出

1 2 1
1 2 4 1
no arbitrage sequence exists

题解

注意到题目要求1) 兑换次数最少 2)兑换次数不超过n次。如果忽略兑换次数,仅考虑从某种货币出发,最后兑换回本币这个问题,显然Floyd很合适。但是本题限制了兑换次数,我们考虑魔改一下Floyd算法,分层dp就可以了。

#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 30;

double dp[N][N][N];
int path[N][N][N];

void output(int i, int j, int t) {
    if (t == 0) printf("%d", i);
    else {
        output(i, path[i][j][t], t - 1);
        printf(" %d", j);
    }
}

int main() {
    int t, i, j, k, n;

    while (~scanf("%d", &n)) {
        memset(dp, 0, sizeof dp);
        FOR(i,1,n) FOR(j,1,n) {
            if (i == j) continue;
            scanf("%lf", &dp[i][j][1]);
            path[i][j][1] = i;
        }

        FOR(t,2,n) FOR(k,1,n) FOR(i,1,n) FOR(j,1,n)
            if (dp[i][j][t] < dp[i][k][t - 1] * dp[k][j][1]) {
                dp[i][j][t] = dp[i][k][t - 1] * dp[k][j][1];
                path[i][j][t] = k;
            }
        FOR(t,2,n) FOR(i,1,n) {
            if (dp[i][i][t] > 1.01) {
                output(i, i, t);
                goto end;
            }
        }
        printf("no arbitrage sequence exists");
        end: putchar('\n');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值