// Arup Guha
// 6/18/2013 (WA on live archive, passes UCF data)
// Attempted Solution to 2005 World Finals Problem C: Traveling Judges

import java.util.*;
import java.io.*;

public class judges {

	public static int n;
	public static int endCity;
	public static edge[] roads;
	public static int judgeMask;
	public static int[] judges;

	public static void main(String[] args) throws Exception {

		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tok = new StringTokenizer(stdin.readLine());

		n = Integer.parseInt(tok.nextToken());
		int loop = 1;
		boolean notfirst = false;

		// Go through each case.
		while (n != -1) {

			while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
			endCity = Integer.parseInt(tok.nextToken())-1;
			while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
			int numRoads = Integer.parseInt(tok.nextToken());

			roads = new edge[numRoads];

			// Read in roads.
			for (int i=0; i<numRoads; i++) {
				while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
				int v1 = Integer.parseInt(tok.nextToken()) - 1;
				while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
				int v2 = Integer.parseInt(tok.nextToken()) - 1;
				while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
				int w = Integer.parseInt(tok.nextToken());
				roads[i] = new edge((1 << v1) + (1 << v2), w);
			}

			// Need for Kruskal's so do now.
			Arrays.sort(roads);

			while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
			int numJudges = Integer.parseInt(tok.nextToken());

			// Store judges in a mask.
			judgeMask =  (1 << endCity);
			judges = new int[numJudges];
			for (int i=0; i<numJudges; i++) {
				if (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
				int item = Integer.parseInt(tok.nextToken()) - 1;
				judgeMask |= (1 << item);
				judges[i] = item;
			}

			if (notfirst) System.out.println();
			solve(loop);

			// Get next case.
			while (!tok.hasMoreTokens()) tok = new StringTokenizer(stdin.readLine());
			n = Integer.parseInt(tok.nextToken());
			loop++;
			notfirst = true;
		}
	}

	public static void solve(int caseNum) {

		// Silly case - needed to avoid Array out of Bounds.
		if (judges.length == 0) {
			System.out.println("Case "+caseNum+": distance = 0");
			return;
		}

		// Go through subsets of cities in proper order.
		subset[] list = new subset[1 << n];
		for (int i=0; i<list.length; i++)
			list[i] = new subset(i);
		Arrays.sort(list);

		// Must be replaced.
		int minDist = -1;
		int best = 0;

		// Go through each subset in order.
		for (int i=0; i<list.length; i++) {

			// Any viable subset must have all judges in it.
			if ((list[i].mask & judgeMask) != judgeMask) continue;

			int thisTree = getMST(list[i]);

			// Can't form a tree.
			if (thisTree == -1) continue;

			// This tree is better, so save it.
			if (minDist == -1 || thisTree < minDist) {
				minDist = thisTree;
				best = list[i].mask;
			}
		}

		// Beginning of output.
		System.out.println("Case "+caseNum+": distance = "+minDist);

		// Now print out paths.
		outputPaths(best);
	}

	// Prints out the paths that correspond to the MST for bitmask best.
	public static void outputPaths(int best) {

		edge[] tree = getMSTEdges(new subset(best));

		ArrayList[] edgeList = new ArrayList[n];
		for (int i=0; i<n; i++)
			edgeList[i] = new ArrayList<Integer>();

		// Build edge list.
		for (int i=0; i<tree.length; i++) {
			int[] verts = getVerts(tree[i].mask);
			edgeList[verts[0]].add(verts[1]);
			edgeList[verts[1]].add(verts[0]);
		}

		// Set up DFS to find paths.
		int[] prev = new int[n];
		Arrays.fill(prev, -1);
		boolean[] visited = new boolean[n];

		// Run search.
		dfs(endCity, edgeList, prev, visited);

		// Build each path from start city back to the destination.
		for (int i=0; i<judges.length; i++) {

			ArrayList<Integer> path = new ArrayList<Integer>();

			// Start here and go backwards.
			int cur = judges[i];
			path.add(cur);
			while (cur != endCity) {
				cur = prev[cur];
				path.add(cur);
			}

			// Print out this path.
			System.out.print("   ");
			for (int j=0; j<path.size()-1; j++)
				System.out.print((1+path.get(j))+"-");
			System.out.println(1+path.get(path.size()-1));
		}

	}

	// Typical dfs that also fills in a last array, noting from which node a given node was
	// discovered.
	public static void dfs(int node, ArrayList[] edgeList, int[] prev, boolean[] visited) {

		// Mark this node.
		visited[node] = true;

		for (int i=0; i<edgeList[node].size(); i++) {
			if (!visited[(Integer)edgeList[node].get(i)]) {
				prev[(Integer)edgeList[node].get(i)] = node;
				dfs((Integer)edgeList[node].get(i), edgeList, prev, visited);
			}
		}
	}

	// Returns the weight of the MST for the bitmask of nodes represented by sub.
	public static int getMST(subset sub) {

		int curTreeMask = 0, curEdge = 0, i = 0, cost = 0;
		edge[] tree = new edge[sub.bits-1];

		// Use for Kruskal's.
		dset myDset = new dset(n);

		// Run Kruskal's.
		while (curEdge < tree.length && i < roads.length) {

			edge next = roads[i];

			// Not a valid edge.
			if ((next.mask & sub.mask) != next.mask) {
				i++;
				continue;
			}

			int[] verts = getVerts(next.mask);

			// No cycle formed and edge is in subset, so add.
			if (myDset.union(verts[0], verts[1]))	{
				tree[curEdge++] = next;
				curTreeMask = curTreeMask | next.mask;
				cost += next.dist;
			}
			i++;
		}

		// Here is our MST cost.
		if (curEdge < tree.length) return -1;
		return cost;
	}

	// Precondition: the set of nodes represented by bitmask sub must have a valid MST.
	// Postcondition: An array of edges in a MST of this bitmask of nodes is returned.
	public static edge[] getMSTEdges(subset sub) {

		int curTreeMask = 0, curEdge = 0, i = 0, cost = 0;
		edge[] tree = new edge[sub.bits-1];

		// Use for Kruskal's.
		dset myDset = new dset(n);

		// Run Kruskal's.
		while (curEdge < tree.length) {

			edge next = roads[i];

			// Not a valid edge.
			if ((next.mask & sub.mask) != next.mask) {
				i++;
				continue;
			}

			int[] verts = getVerts(next.mask);

			// No cycle formed and edge is in subset, so add.
			if (myDset.union(verts[0], verts[1]))	{
				tree[curEdge++] = next;
				curTreeMask = curTreeMask | next.mask;
				cost += next.dist;
			}
			i++;
		}

		// Return MST
		return tree;
	}

	// Precondition: myMask has exactly 2 bits on.
	// Postcondition: Returns the placement of those 2 bits in an array.
	public static int[] getVerts(int myMask) {

		int i = 0, j=0;
		int[] ans = new int[2];
		while (myMask > 0) {
			if ((myMask & 1) == 1) {
				ans[j++] = i;
			}
			i++;
			myMask = myMask >> 1;
		}
		return ans;
	}

}

//  Just used for the Disjoint set class.
class pair {
	public int parent;
	public int height;

	public pair(int a, int b) {
		parent = a;
		height = b;
	}
}

// Disjoint Set with path compression.
class dset {

	private pair[] parents;

	public dset(int n) {
		parents = new pair[n];
		for (int i=0; i<n; i++)
			parents[i] = new pair(i,0);
	}

	public int find(int child) {

		// Implements Path Compression - directly links each node in path to root.
		if (parents[child].parent != child) {
			parents[child].parent = find(parents[child].parent);
			parents[child].height = 1;
		}

		// The root in each case is the parent of the initial call node.
		return parents[child].parent;
	}


	public boolean union(int c1, int c2) {
		int root1 = find(c1);
		int root2 = find(c2);

		// Nothing to union.
		if (root1 == root2)
			return false;

		// Root 1 stays parent.
		if (parents[root1].height > parents[root2].height) {
			parents[root2].parent = root1;
		}

		// Tie case get assigned to root 1 also.
		else if (parents[root1].height == parents[root2].height) {
			parents[root2].parent = root1;
			parents[root1].height++;
		}

		// Must use root 2 here.
		else {
			parents[root1].parent = root2;
		}

		return true;
	}
}

// How we'll sort edges for Kruskal's
class edge implements Comparable<edge> {

	public int mask;
	public int dist;

	public edge(int myMask, int myDist) {
		mask = myMask;
		dist = myDist;
	}

	public int compareTo(edge other) {
		return this.dist - other.dist;
	}
}

// Allows us to sort the subsets in the order we must consider them for all the given tiebreakers.
class subset implements Comparable<subset> {

	public int mask;
	public int bits;
	public subset(int n) {
		mask = n;
		bits = numBits();
	}

	public int numBits() {

		int n = mask, cnt = 0;
		while (n > 0) {
			cnt = cnt + (n & 1);
			n = n >> 1;
		}
		return cnt;
	}

	// First, number of bits matters. If those are tied, then we find the lexicographically
	// first subset. This would have been easier if I stored the bitmask in reverse order, but
	// that would have probably caused other errors.
	public int compareTo(subset other) {

		if (this.bits != other.bits)
			return this.bits - other.bits;

		int thisM = mask, otherM = other.mask;

		// Least significant bits matter most, so peel them off and answer
		// the first time you see a difference.
		while (thisM > 0 || otherM > 0) {

			if ((thisM & 1) != (otherM &1)) {
				if ((thisM & 1) == 1) return -1;
				return 1;
			}
			thisM = thisM >> 1;
			otherM = otherM >> 1;
		}
		return 0;
	}
}