java - 已知外匯牌價(jià)折算匯率
問題描述
碰到了一個(gè)關(guān)于元組的算法問題
請(qǐng)大家?guī)兔纯?能不能給個(gè)答案,或者解決思路也行.
謝謝!
三元組(a,b,c)標(biāo)識(shí)a幣種到b幣種的匯率為c,反向亦成立。輸入一堆這樣的三元組,再指定兩個(gè)幣種x y,問x->y的匯率是多少?請(qǐng)編程實(shí)現(xiàn),并給出時(shí)間、空間復(fù)雜度。注意:x->y的匯率是唯一的。
問題解答
回答1:思路:三元組 -> 有向圖 -> 求任兩節(jié)點(diǎn)的路徑 -> 矩陣乘法或Floyd-Warshal。
比如獲取的外匯牌價(jià)是:
第一行表示,每1元人民幣可以兌換0.116英鎊。每個(gè)三元組(c1, c2, r)對(duì)應(yīng)兩條帶權(quán)重的邊:c1 -> c2 weighted r和c2 -> c1 weighted 1/r。這些牌價(jià)實(shí)際上給出一個(gè)有向圖:
這里假設(shè)給出的三元組不會(huì)導(dǎo)出矛盾,且有向圖是聯(lián)通的(不會(huì)有折算不到的情況)。這個(gè)有向圖寫成帶權(quán)重的鄰接矩陣就是:
矩陣元素A[i,j]表示1單位i幣種可以兌換多少單位的j幣種。矩陣中的零代表目前匯率未知。
矩陣乘法把矩陣A連乘可以逐步去除這些零元素。但是要把普通矩陣相乘中計(jì)算點(diǎn)積的加法替換成“取第一個(gè)大于零的數(shù),若沒有則為零”的操作。例如:(1,2,3).(0,3,2) = first_positive(1*0, 2*3, 3*2) = 6。
用“匯率乘法”計(jì)算A的乘方,A^k表示最多經(jīng)過k-1步折算得到的匯率表,一直算到A^k中沒有零停止。如果有n種貨幣,最多計(jì)算到A^(n-1)。
A^3:
觀察A^3的第一行,它是所有貨幣對(duì)人民幣的比價(jià)。任兩種貨幣的比價(jià)就是把它們對(duì)人民幣的比價(jià)的商。所以其實(shí)一開始用A的第一行參加計(jì)算就好:A[1] * A * ... * A (最多n-1次),每次進(jìn)行的是行向量和矩陣的乘法,直到行的所有元素非零結(jié)束。這個(gè)計(jì)算的復(fù)雜度是O(n3)。
Floyd-Warshal調(diào)整一下求最短路徑算法Floyd-Warshal中的遞推關(guān)系,也可以用于本題的匯率折算。Floyd-Warshal的復(fù)雜度是Θ(n3)。所以用矩陣乘法可能會(huì)更快一些。
for k from 1 to rows(A) for i from 1 to rows(A)for j from 1 to rows(A) if A[i][j] = 0 then // 貨幣 i, j 通過貨幣 k 折算 A[i][j] <- A[i][k] * A[k][j] end if
兩種算法都需要存儲(chǔ)匯率矩陣,所以的空間復(fù)雜度都是Θ(n2)。
回答2:如果是提供三元組數(shù)組,生成一個(gè)計(jì)算 x->y 匯率的方式的最優(yōu)解: 有向圖最短路徑算法
如果是每次提供不同的三元組數(shù)組,只需要獲取一個(gè)結(jié)果就好: 有向圖尋路算法
回答3:元組可以作為 dict 的 key
>>> ls = [(’人民幣’, ’美元’), (’人民幣’, ’歐元’), (’人民幣’, ’英鎊’)]>>> 匯率表 = dict(zip(ls,(6.,7.,8.))){(’人民幣’, ’美元’): 6.0, (’人民幣’, ’英鎊’): 8.0, (’人民幣’, ’歐元’): 7.0}>>> import pprint>>> pprint.pprint(匯率表,width=10){(’人民幣’, ’歐元’): 7.0, (’人民幣’, ’美元’): 6.0, (’人民幣’, ’英鎊’): 8.0}>>> 匯率表[(’人民幣’, ’美元’)]6.0回答4:
上面的有些算法寫得好復(fù)雜,寫個(gè)簡(jiǎn)單的:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>typedef struct node{ char *str; /*拼接后的字符串*/ float value; /*匯率值*/}node_t;int main(int argc, char *argv[]){ /*用戶輸入的一序列匯率對(duì)應(yīng)關(guān)系*/ static char const *buff[] = {'CNY','GBP','0.116','CNY','RUB','8.406','CNY','AUD','0.184','JPY','RUB','0.5072','USD','EUR', '0.9456'};int npairs = sizeof(buff)/sizeof(buff[0])/3; node_t * buf = calloc(1,npairs*sizeof(node_t)); if(NULL == buf){ printf('calloc is null !n');return(-1); } int i = 0; int j = 0; int len = 0; char tmp[16] = {’0’}; for(i=0;i<npairs*3; i+= 3){memset(tmp,’0’,sizeof(tmp));/*把兩個(gè)字符串進(jìn)行拼接*/snprintf(tmp,16,'%s%s',buff[i],buff[i+1]);len = strlen(tmp);buf[j].str = calloc(1,sizeof(char)*(len+1));if(NULL != buf[j].str){ memmove(buf[j].str,tmp,len); buf[j].value = atof(buff[i+2]); j += 1;} } printf('please input the two node:n'); char input0[8] = {’0’}; char input1[8] = {’0’};scanf('%s%s',input0,input1); char data0[16] = {’0’}; char data1[16] = {’0’}; /*考慮正序和反序*/ snprintf(data0,16,'%s%s',input0,input1); snprintf(data1,16,'%s%s',input1,input0); for(i=0;i<j;++i){/*輪訓(xùn)匹配*/if((0==strcmp(buf[i].str,data0))){ printf('%s->%s %f n',input0,input1,buf[i].value); break;}if( 0==strcmp(buf[i].str,data1) ){ printf('%s->%s %f n',input1,input0,buf[i].value); break;} } if(i==j){ printf('can not find the pair n');} /* add the free*/ return 0;}
測(cè)試結(jié)果如下:
[field@learn]$./test_hello please input the two node:CNY GBPCNY->GBP 0.116000 [field@learn]$./test_hello please input the two node:GBP CNYCNY->GBP 0.116000 [field@learn]$
這里利用的是幣種名字的唯一性,兩個(gè)幣種拼接在一起必然也是唯一的。
相關(guān)文章:
1. thinkPHP5中獲取數(shù)據(jù)庫數(shù)據(jù)后默認(rèn)選中下拉框的值,傳遞到后臺(tái)消失不見。有圖有代碼,希望有人幫忙2. 求救一下,用新版的phpstudy,數(shù)據(jù)庫過段時(shí)間會(huì)消失是什么情況?3. linux運(yùn)維 - python遠(yuǎn)程控制windows如何實(shí)現(xiàn)4. Python2中code.co_kwonlyargcount的等效寫法5. python - 如何對(duì)列表中的列表進(jìn)行頻率統(tǒng)計(jì)?6. django - Python error: [Errno 99] Cannot assign requested address7. mysql數(shù)據(jù)庫做關(guān)聯(lián)一般用id還是用戶名8. javascript - 如何用最快的速度C#或Python開發(fā)一個(gè)桌面應(yīng)用程序來訪問我的網(wǎng)站?9. python小白,關(guān)于函數(shù)問題10. python小白 關(guān)于類里面的方法獲取變量失敗的問題
