#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
void Code_By_Mohamed_Khaled() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
}
double a; // initial amount
string initCrypto; // initial currency
ll N; // number of opportunities
vector<string> baseC, quoteC;
vector<double> priceP;
// For each currency, list of indices where it appears as base or quote
unordered_map<string, vector<int>> mpBase, mpQuote;
// memo[i][cur] = best value of 1 unit of cur in terms of initial crypto
vector<unordered_map<string,double>> memo;
double dp_solve(int idx, const string &cur) {
if (idx == N) {
// if no more opportunities, only 1 unit of initial currency has value 1,
// others have 0 value
return (cur == initCrypto ? 1.0 : 0.0);
}
auto it = memo[idx].find(cur);
if (it != memo[idx].end()) return it->second;
double best = (cur == initCrypto ? 1.0 : 0.0);
// try using any future opportunity where cur is the base currency
auto &vecB = mpBase[cur];
auto itB = lower_bound(vecB.begin(), vecB.end(), idx);
while (itB != vecB.end()) {
int j = *itB;
// convert 1 unit cur -> priceP[j] units of quoteC[j]
double val = priceP[j] * dp_solve(j+1, quoteC[j]);
best = max(best, val);
++itB;
}
// try using any future opportunity where cur is the quote currency
auto &vecQ = mpQuote[cur];
auto itQ = lower_bound(vecQ.begin(), vecQ.end(), idx);
while (itQ != vecQ.end()) {
int j = *itQ;
// convert 1 unit cur -> (1/priceP[j]) units of baseC[j]
double val = (1.0/priceP[j]) * dp_solve(j+1, baseC[j]);
best = max(best, val);
++itQ;
}
return memo[idx][cur] = best;
}
int main() {
Code_By_Mohamed_Khaled();
cout << fixed << setprecision(6);
ll t;
cin >> t;
while (t--) {
cin >> a >> initCrypto >> N;
baseC.assign(N, "");
quoteC.assign(N, "");
priceP.assign(N, 0.0);
mpBase.clear();
mpQuote.clear();
memo.clear();
memo.resize(N+1);
for (int i = 0; i < N; i++) {
cin >> baseC[i] >> quoteC[i] >> priceP[i];
mpBase[baseC[i]].push_back(i);
mpQuote[quoteC[i]].push_back(i);
}
// ensure index lists are sorted (they are in insertion order already)
// but just in case:
for (auto &p : mpBase) sort(p.second.begin(), p.second.end());
for (auto &p : mpQuote) sort(p.second.begin(), p.second.end());
// solve for value of 1 unit of initCrypto
double rate = dp_solve(0, initCrypto);
// multiply by initial amount
double answer = rate * a;
cout << answer << "\n";
}
return 0;
}