// Arup Guha
// 1/20/2015
// Solution to 2005 MCPC Problem H: Leapin' Lizards

import java.util.*;

public class h {

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int numCases = stdin.nextInt();

		// Process all cases.
		for (int loop=1; loop<=numCases; loop++) {

			int r = stdin.nextInt();
			int d = stdin.nextInt();
			int c = 0;

			// Read in jumps from pillars.
			int[][] jumps = new int[r][];
			for (int i=0; i<r; i++) {
				String s = stdin.next();
				c = s.length();
				jumps[i] = new int[c];
				for (int j=0; j<c; j++)
					jumps[i][j] = s.charAt(j) - '0';
			}

			// Read in lizard positions.
			char[][] lizards = new char[r][c];
			int numLizards = 0;
			for (int i=0; i<r; i++) {
				lizards[i] = stdin.next().toCharArray();
				for (int j=0; j<c; j++)
					if (lizards[i][j] == 'L')
						numLizards++;
			}

			// Set up flow graph and solve.
			Edge[][] graph = makeFlowGraph(jumps, lizards, numLizards, r, c, d);
			netflowdinic myFlow = new netflowdinic(graph, graph.length-2, graph.length-1);
			int res = numLizards - myFlow.getMaxFlow();

			// Super annoying output format.
			if (res > 1)
				System.out.println("Case #"+loop+": "+res+" lizards were left behind.");
			else if (res == 1)
				System.out.println("Case #"+loop+": "+res+" lizard was left behind.");
			else
				System.out.println("Case #"+loop+": no lizard was left behind.");
		}
	}

	// Returns a flow graph whose max flow is equal to the solution of the problem.
	public static Edge[][] makeFlowGraph(int[][] jumps, char[][] lizards, int numLizards,int r, int c, int distance) {

		// We create two nodes for each grid square, plus a source and sink.
		int v = 2*r*c+2;
		Edge[][] graph = new Edge[v][];

		// Set up edges out of each "top" grid vertex - restricts number of jumps off each grid square.
		for (int i=0; i<r*c; i++) {
			graph[i] = new Edge[1];
			graph[i][0] = new Edge(jumps[i/c][i%c], i+r*c);
		}

		// Set up edges out of each "bottom" grid vertex - where lizards can jump to, from each square.
		for (int j=r*c; j<2*r*c; j++) {

			// Convert to regular x,y coordinates.
			int bottomX = (j-r*c)/c, bottomY = (j-r*c)%c;

			// Add in each edge to where a lizard from this square can jump.
			ArrayList<Edge> tmp = new ArrayList<Edge>();
			for (int i=0; i<r*c; i++) {
				if (i%(r*c) == j%(r*c)) continue;
				int topX = i/c, topY = i%c;
				int thisDsq = (topX-bottomX)*(topX-bottomX) + (topY-bottomY)*(topY-bottomY);
				if (thisDsq <= distance*distance)
					tmp.add(new Edge(3, i));
			}
			if (toSafety(bottomX, bottomY, r, c, distance)) tmp.add(new Edge(3, v-1));

			// Copy edges...
			graph[j] = new Edge[tmp.size()];
			for (int i=0; i<graph[j].length; i++)
				graph[j][i] = tmp.get(i);
		}

		// Source - just link to each square with a lizard, initially.
		graph[v-2] = new Edge[numLizards];
		int cnt = 0;
		for (int i=0; i<r*c; i++)
			if (lizards[i/c][i%c] == 'L')
				graph[v-2][cnt++] = new Edge(1, i);

		// Sink...
		graph[v-1] = new Edge[0];

		// We're finally done =)
		return graph;
	}

	// Returns true if we can jump to safety from (startX, startY) on an r x c grid and jumping distance d.
	public static boolean toSafety(int startX, int startY, int r, int c, int d) {
		return r-startX <= d || c-startY <=d || startX+1 <= d || startY+1 <= d;
	}
}

/*** From here on is my network flow code for Dinic's ***/
class Edge {

	public int dest;
	public int capacity;
	public int flow;

	public Edge(int cap, int d) {
		capacity = cap;
		flow = 0;
		dest = d;
	}

	public String toString() {
		return "("+dest+" "+capacity+", "+flow+") ";
	}

	public int maxPushForward() {
		return capacity - flow;
	}

	public int maxPushBackward() {
		return flow;
	}

	public boolean pushForward(int moreflow) {

		// We can't push through this much flow.
		if (flow+moreflow > capacity)
			return false;

		// Push through.
		flow += moreflow;
		return true;
	}

	public boolean pushBack(int lessflow) {

		// Not enough to push back on.
		if (flow < lessflow)
			return false;

		flow -= lessflow;
		return true;
	}
}

class direction {

	public int prev;
	public boolean forward;

	public direction(int node, boolean dir) {
		prev = node;
		forward = dir;
	}

	public String toString() {
		if (forward)
			return "" + prev + "->";
		else
			return "" + prev + "<-";
	}
}

class pair {

	public int vertex;
	public int distance;

	public pair(int v, int d) {
		vertex = v;
		distance = d;
	}
}

class netflowdinic {

	private Edge[][] adjMat;
	private int source;
	private int dest;
	private HashMap[] lookup;
	private LinkedList[] backEdgeLookup;
	private int[] distance;

	public netflowdinic(Edge[][] matrix, int start, int end) {

		// Set up easy stuff.
		adjMat = matrix;
		source = start;
		dest = end;
		lookup = new HashMap[matrix.length];
		distance = new int[matrix.length];

		// Allocate empty LLs.
		backEdgeLookup = new LinkedList[matrix.length];
		for (int i=0; i<matrix.length; i++)
			backEdgeLookup[i] = new LinkedList<Integer>();

		// Fill these in.
		for (int i=0; i<adjMat.length; i++) {

			lookup[i] = new HashMap<Integer,Integer>();
			for (int j=0; j<adjMat[i].length; j++) {
				backEdgeLookup[adjMat[i][j].dest].offer(i);
				lookup[i].put(adjMat[i][j].dest,j);
				adjMat[i][j].flow = 0;
			}
		}

	}

	// Wrapper function for dfs that finds an augmenting path of a specific length.
	public ArrayList<direction> findAugmentingPath() {
		boolean[] used = new boolean[adjMat.length];
		ArrayList<direction> path = new ArrayList<direction>();
		path.add(new direction(source, true));
		path = findAugmentingPathRec(source, used, path);
		if (path == null) return null;
		return fix(path);
	}

	// Recursive function that builds the augmenting path from next to dest.
	public ArrayList<direction> findAugmentingPathRec(int next, boolean[] used, ArrayList<direction> path) {

		// We're done.
		if (next == dest) return path;

		// Mark this node.
		used[next] = true;
		int curDist = distance[next];

		// Find all neighbors and add into the queue. These are forward edges.
		for (int i=0; i<adjMat[next].length; i++) {

			int item = adjMat[next][i].dest;
			if (!used[item] && adjMat[next][i].maxPushForward() > 0 && distance[item] == curDist+1) {
				path.add(new direction(item, true));
				ArrayList<direction> temp = findAugmentingPathRec(item, used, path);
				if (temp != null)
					return temp;
				else
					path.remove(path.size()-1);
			}
		}

		// Now look for back edges.
		for (int i=0; i<backEdgeLookup[next].size(); i++) {

			int item = (Integer)backEdgeLookup[next].pollFirst();
			if (!used[item] && lookup[item].containsKey(next) && adjMat[item][(Integer)(lookup[item].get(next))].maxPushBackward() > 0 && distance[item] == curDist+1) {
				path.add(new direction(item, false));
				ArrayList<direction> temp = findAugmentingPathRec(item, used, path);
				if (temp != null)
					return temp;
				else
					path.remove(path.size()-1);
			}
			backEdgeLookup[next].offer(item);
		}

		return null;
	}

	// This is to fix the faulty output of the recursive functions. The directions are "off by one".
	public static ArrayList<direction> fix(ArrayList<direction> list) {
		for (int i=0; i<list.size()-1; i++)
			list.get(i).forward = list.get(i+1).forward;
		return list;
	}

	// This is the BFS that labels all of the distances from the source.
	public boolean labelDistances() {

		Arrays.fill(distance, -1);

		// Set up BFS.
		boolean[] inQueue = new boolean[adjMat.length];
		for (int i=0; i<inQueue.length; i++)
			inQueue[i] = false;

		LinkedList<pair> bfs_queue = new LinkedList<pair>();
		bfs_queue.offer(new pair(source, 0));
		inQueue[source] = true;

		// Our BFS will go until we clear out the queue.
		while (bfs_queue.size() > 0) {

			// Add all the new neighbors of the current node.
			pair nextItem = bfs_queue.poll();
			int next = nextItem.vertex;

			// Store distance from source.
			distance[next] = nextItem.distance;

			// Find all neighbors and add into the queue. These are forward edges.
			for (int i=0; i<adjMat[next].length; i++) {

				int item = adjMat[next][i].dest;
				if (!inQueue[item] && adjMat[next][i].maxPushForward() > 0) {
					bfs_queue.offer(new pair(item, nextItem.distance+1) );
					inQueue[item] = true;
				}
			}

			// Now look for back edges.
			for (int i=0; i<backEdgeLookup[next].size(); i++) {

				int item = (Integer)backEdgeLookup[next].pollFirst();
				if (!inQueue[item] && lookup[item].containsKey(next) && adjMat[item][(Integer)(lookup[item].get(next))].maxPushBackward() > 0) {
					bfs_queue.offer(new pair(item, nextItem.distance+1));
					inQueue[item] = true;
				}
				backEdgeLookup[next].offer(item);
			}
		}

		// No augmenting path found.
		return inQueue[dest];
	}


	// Run the Max Flow Algorithm here.
	public int getMaxFlow() {

		int flow = 0;

		// Outer level - do BFS to label nodes.
		while (labelDistances()) {

			ArrayList<direction> nextpath = findAugmentingPath();

			// Run adjusted DFS here.
			while (nextpath != null) {



				// Check what the best flow through this path is.
				int this_flow = Integer.MAX_VALUE;
				for (int i=0; i<nextpath.size()-1; i++) {

					if (nextpath.get(i).forward) {
						this_flow = Math.min(this_flow, adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].maxPushForward());
					}
					else {
						this_flow = Math.min(this_flow, adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].maxPushBackward());
					}
				}

				// Now, put this flow through.
				for (int i=0; i<nextpath.size()-1; i++) {

					if (nextpath.get(i).forward) {
						adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].pushForward(this_flow);
					}
					else {
						adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].pushBack(this_flow);
					}
				}

				// Add this flow in and then get the next path.
				flow += this_flow;
				nextpath = findAugmentingPath();
			}
		}

		return flow;
	}
}