/* * Sample solution to Easter Holidays * Author: Mikael Goldmann */ import java.io.*; import java.util.*; class holidays_mg { static BufferedReader stdin; static final int infty = 1<<30; public static void main(String[] s) throws Exception { Reader r = new InputStreamReader(System.in); stdin = new BufferedReader(r); (new holidays_mg()).run(); } void run() throws Exception { int ncases=Integer.parseInt(stdin.readLine()); for (int i = 0; i < ncases; ++i) solve(i+1); } void solve(int casenum) throws Exception { int n,m,k; StringTokenizer st; st = new StringTokenizer(stdin.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); k = Integer.parseInt(st.nextToken()); /* read input into int arrays */ int[] slopefrom = new int[m]; int[] slopeto = new int[m]; int[] slopecost = new int[m]; int[] liftfrom = new int[k]; int[] liftto = new int[k]; int[] liftcost = new int[k]; int[] nslopes = new int[n+1]; int[] nlifts = new int[n+1]; for (int i = 0; i < m; ++i) { st = new StringTokenizer(stdin.readLine()); slopefrom[i] = Integer.parseInt(st.nextToken()); slopeto[i] = Integer.parseInt(st.nextToken()); slopecost[i] = Integer.parseInt(st.nextToken()); ++nslopes[slopeto[i]]; } for (int i = 0; i < k; ++i) { st = new StringTokenizer(stdin.readLine()); liftfrom[i] = Integer.parseInt(st.nextToken()); liftto[i] = Integer.parseInt(st.nextToken()); liftcost[i] = Integer.parseInt(st.nextToken()); ++nlifts[liftfrom[i]]; } /* slopes are modelled as edgees FROM the lower point (i.e., the "to") lifts are modelled as edgees FROM the lower point (i.e., the "from") For each place i, lift[i] is an array of places it has lifts to and lcost[i] is an array of the correspoding costs. Similarly for slope[i] and scost[i]. Note that slopes go up and are given negative costs! */ int[][] lift = new int[n+1][]; int[][] slope = new int[n+1][]; int[][] lcost = new int[n+1][]; int[][] scost = new int[n+1][]; int[] lcnt = new int[n+1]; int[] scnt = new int[n+1]; for (int i=1; i<=n; ++i) { lift[i] = new int[nlifts[i]]; lcost[i] = new int[nlifts[i]]; slope[i] = new int[nslopes[i]]; scost[i] = new int[nslopes[i]]; } for (int i = 0; i < m; ++i) { int a = slopeto[i]; int b = slopefrom[i]; int c = -slopecost[i]; slope[a][scnt[a]] = b; scost[a][scnt[a]] = c; ++scnt[a]; } for (int i = 0; i < k; ++i) { int a = liftfrom[i]; int b = liftto[i]; int c = liftcost[i]; lift[a][lcnt[a]] = b; lcost[a][lcnt[a]] = c; ++lcnt[a]; } /* us[1..n] will hold places sorted topologically by slopes */ /* ul[1..n] will hold places sorted topologically by lifts */ /* int[] us = new int[n+1]; int[] ul = new int[n+1]; topsort(n, us, slope); topsort(n, ul, lift); */ int[] ds = new int[n+1]; int[] dl = new int[n+1]; int[] sp = new int[n+1]; // backpointer int[] lp = new int[n+1]; // backpointer double best = -1.0; int bestlen = 0; int[] besttrip = new int[2*n]; int[] aux = new int[n]; for (int i = 1; i <= n; ++i) { Arrays.fill(ds, infty); Arrays.fill(dl, infty); DAGshortestPath(n, i, slope, scost, ds, sp); /* for (int ii = 1; ii <= n; ++ii) System.err.println(ii +": " + ds[ii] + ", " + sp[ii]); */ DAGshortestPath(n, i, lift, lcost, dl, lp); /* for (int ii = 1; ii <= n; ++ii) System.err.println(ii +": " + dl[ii] + ", " + lp[ii]); */ for (int j = 1; j <= n; ++j) { if (dl[j] < infty && ds[j] < infty && dl[j] != 0) { double score = -ds[j]; score /= dl[j]; if (score > best) { best = score; /* System.err.println("i= " + i + " j= " +j); System.err.println("ds= " + ds[j] + " dl= " +dl[j]); */ // save the trip int len1=0; int tmp = j; besttrip[len1++] = j; while (tmp != i) { tmp = lp[tmp]; besttrip[len1++] = tmp; } int len2 = 0; tmp = j; while (tmp != i) { aux[len2++] = tmp; tmp = sp[tmp]; } for (int jj=len2-1; jj >= 0; --jj) besttrip[len1++] = aux[jj]; bestlen = len1; } } } } System.out.print(besttrip[0]); for (int i = 1; i < bestlen; ++i) System.out.print(" " + besttrip[i]); System.out.println(); long bst = Math.round(1000*best); System.out.print(bst/1000 + "."); bst %= 1000; int tt = 100; for (int ii = 0; ii < 3; ++ii) { System.out.print(bst/tt); bst %= tt; tt /= 10; } System.out.println(); } void DAGshortestPath(int n, int start, int[][]edges, int[][] costs, int[] dist, int[] prev) { boolean[] visited = new boolean[n+1]; dist[start] = 0; visited[start] = true; for (int i = 1; i <= n; ++i) if (!visited[i]) dfs(i, edges, costs, dist, prev, visited); } void dfs(int u, int[][] e, int[][] c, int[] d, int[] p, boolean[] v) { int m = e[u].length; v[u] = true; for (int i = 0; i < m; ++i) { int w = e[u][i]; if (!v[w]) dfs(w, e, c, d, p, v); if (d[w] != infty && d[u] > d[w] + c[u][i]) { p[u] = w; d[u] = d[w] + c[u][i]; } } } }