// Arup Guha
// 8/29/2016
// Solution to 2016 UCF Locals Problem: Rising Tides

import java.util.*;

public class tides_arup {

	// Possible directions of movement.
	final public static int[] DX = {-1,0,0,1};
	final public static int[] DY = {0,-1,1,0};

	final public static int IMPOSSIBLE = -1;
	final public static int UNVISITED = -2;
	final public static int MAX = 1000000000;

	// Stores original grid.
	public static int r;
	public static int c;
	public static int[][] grid;
	public static int max;

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int numCases = stdin.nextInt();

		// Process each case.
		for (int loop=0; loop<numCases; loop++) {

			// Read in this grid.
			r = stdin.nextInt();
			c = stdin.nextInt();
			grid = new int[r][c];
			for (int i=0; i<r; i++)
				for (int j=0; j<c; j++)
					grid[i][j] = stdin.nextInt();

			// Screen out all impossible cases.
			if (!canDo(1))
				System.out.println("impossible");
			else
				System.out.println(binSearch());
		}
	}

	// Runs a binary search on the optimal answer.
	public static int binSearch() {

		int low = 1, high = MAX;

		// Run a typical binary search.
		while (low < high) {

			// Strange but the +1 avoids the infinite loop...
			int mid = (low+high+1)/2;

			// We got this height to work, our answer is at least this big.
			if (canDo(mid))
				low = mid;

			// It didn't work, so best we can do is this.
			else
				high = mid-1;
		}

		// Guaranteed to be our answer!
		return low;
	}

	// Returns true iff we can get out of the caves with a minimum height of offset.
	public static boolean canDo(int offset) {

		// Flooded at the start, so we can't do it.
		if (grid[0][0] < offset) return false;

		// Set up BFS.
		LinkedList<Integer> q = new LinkedList<Integer>();
		q.offer(0);

		// Store results here.
		int[][] res = new int[r][c];
		for (int i=0; i<r; i++)
			Arrays.fill(res[i], UNVISITED);
		res[0][0] = 0;

		// Start BFS.
		while (q.size() > 0) {

			// Get next position.
			int cur = q.poll();
			int curX = cur/c;
			int curY = cur%c;
			int curT = res[curX][curY];

			// We made it!
			if (cur == r*c-1) return true;

			// Try each new direction.
			for (int i=0; i<DX.length; i++) {
				int nextX = curX + DX[i];
				int nextY = curY + DY[i];

				// Out of bounds or previously visited, don't add.
				if (!inbounds(nextX, nextY)) continue;
				if (res[nextX][nextY] != UNVISITED) continue;

				// Can't go here since we're flooded.
				if (grid[nextX][nextY] - curT - offset <= 0) continue;

				// Put in queue and mark time.
				q.offer(c*nextX+nextY);
				res[nextX][nextY] = curT + 1;
			}
		} // end while

		// If we get here, we're screwed.
		return false;
	}

	public static boolean inbounds(int x, int y) {
		return x >= 0 && x < r && y >= 0 && y < c;
	}
}