import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;

public class Main
{
    private int V;   // No. of vertices 
    static boolean isConnected=true;
    // Array  of lists for Adjacency List Representation 
    private LinkedList<Integer> adj[]; 
    int time = 0; 
    static final int NIL = -1; 
  
    // Constructor 
    Main(int v) 
    { 
        V = v; 
        adj = new LinkedList[v]; 
        for (int i=0; i<v; ++i) 
            adj[i] = new LinkedList(); 
    } 
  
    //Function to add an edge into the graph 
    void addEdge(int v, int w) 
    { 
        adj[v].add(w);  // Add w to v's list. 
        adj[w].add(v);    //Add v to w's list 
    } 
  
    // A recursive function that find articulation points using DFS 
    // u --> The vertex to be visited next 
    // visited[] --> keeps tract of visited vertices 
    // disc[] --> Stores discovery times of visited vertices 
    // parent[] --> Stores parent vertices in DFS tree 
    // ap[] --> Store articulation points 
    void APUtil(int u, boolean visited[], int disc[], 
                int low[], int parent[], boolean ap[]) 
    { 
  
        // Count of children in DFS Tree 
        int children = 0; 
  
        // Mark the current node as visited 
        visited[u] = true; 
  
        // Initialize discovery time and low value 
        disc[u] = low[u] = ++time; 
  
        // Go through all vertices aadjacent to this 
        Iterator<Integer> i = adj[u].iterator(); 
        while (i.hasNext()) 
        { 
            int v = i.next();  // v is current adjacent of u 
  
            // If v is not visited yet, then make it a child of u 
            // in DFS tree and recur for it 
            if (!visited[v]) 
            { 
                children++; 
                parent[v] = u; 
                APUtil(v, visited, disc, low, parent, ap); 
  
                // Check if the subtree rooted with v has a connection to 
                // one of the ancestors of u 
                low[u]  = Math.min(low[u], low[v]); 
  
                // u is an articulation point in following cases 
  
                // (1) u is root of DFS tree and has two or more chilren. 
                if (parent[u] == NIL && children > 1) 
                    ap[u] = true; 
  
                // (2) If u is not root and low value of one of its child 
                // is more than discovery value of u. 
                if (parent[u] != NIL && low[v] >= disc[u]) 
                    ap[u] = true; 
            } 
  
            // Update low value of u for parent function calls. 
            else if (v != parent[u]) 
                low[u]  = Math.min(low[u], disc[v]); 
        } 
    } 
  
    // The function to do DFS traversal. It uses recursive function APUtil() 
    ArrayList<Integer> AP(int size) 
    { 
        // Mark all the vertices as not visited 
        boolean visited[] = new boolean[V]; 
        int disc[] = new int[V]; 
        int low[] = new int[V]; 
        int parent[] = new int[V]; 
        boolean ap[] = new boolean[V]; // To store articulation points 
  
        // Initialize parent and visited, and ap(articulation point) 
        // arrays 
        for (int i = 0; i < V; i++) 
        { 
            parent[i] = NIL; 
            visited[i] = false; 
            ap[i] = false; 
        } 
  
        // Call the recursive helper function to find articulation 
        // points in DFS tree rooted with vertex 'i' 
        /*for (int i = 0; i < V; i++) 
            if (visited[i] == false) 
                APUtil(i, visited, disc, low, parent, ap); */

  
        APUtil(0, visited, disc, low, parent, ap); 
        if(visited[size-1]==false)
            isConnected=false;

        // Now ap[] contains articulation points, print them 
        ArrayList<Integer> list=new ArrayList<>();
        for (int i = 0; i < V; i++) 
            if (ap[i] == true) 
                list.add(i); 
        return list;
    } 
  
    public static void main(String[] args)
    {
        Scanner in=new Scanner(System.in);
        int t=in.nextInt();
        for(int test=0;test<t;test++)
        {
            int n=in.nextInt();
            char[][] mat=new char[n][n];
            int ones=1;
            int zeroes=1;
            HashMap<Integer,Integer> zmap=new HashMap<>(); 
            HashMap<Integer,Integer> omap=new HashMap<>();
            for(int i=0;i<n;i++)
            {
                String s=in.next();
                for(int j=0;j<n;j++)
                {
                    mat[i][j]=s.charAt(j);
                    if(mat[i][j]=='0')
                    {
                        zmap.put(n*i+j,zeroes);
                        zeroes++;
                    }
                    else if(mat[i][j]=='1')
                    {
                        omap.put(n*i+j,ones);
                        ones++;
                    }
                }
            }
            zmap.put(0,0);
            zmap.put(n*n-1,zeroes);
            omap.put(0,0);
            omap.put(n*n-1,ones);
            zeroes++;
            ones++;
            /*for(Integer i: omap.keySet())
                System.out.println(i+": "+omap.get(i));*/
            Main g1=new Main(zeroes);
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    if(mat[i][j]!='1')
                    {
                        if(i<n-1 && zmap.containsKey(n*(i+1)+j))
                            g1.addEdge(zmap.get(n*i+j),zmap.get(n*(i+1)+j));
                        if(j<n-1 && zmap.containsKey(n*i+j+1))
                            g1.addEdge(zmap.get(n*i+j),zmap.get(n*i+j+1));
                    }
                }
            }
            isConnected=true;
            ArrayList<Integer> Z=g1.AP(zeroes);
            /*for(int i: Z)
                System.out.println(i);*/
            ArrayList<Integer> X=new ArrayList<>();
            ArrayList<Integer> Y=new ArrayList<>(); 
            
            int cnt=0;
            if(isConnected==true && Z.size()!=0)
            {
                cnt++;
                int val=Z.get(Z.size()-1);
                X.add(val/n);
                Y.add(val%n);
            }
            Main g2=new Main(ones);
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    if(mat[i][j]!='0')
                    {
                        //System.out.println(i+" "+j);
                        if(i<n-1 && omap.containsKey(n*(i+1)+j))
                        {
                            //System.out.println(i+","+j+"   "+(i+1)+","+j);
                            g2.addEdge(omap.get(n*i+j),omap.get(n*(i+1)+j));
                        }
                        if(j<n-1 && omap.containsKey(n*i+j+1))
                        {
                            //System.out.println(i+","+j+"   "+i+","+(j+1));
                            g2.addEdge(omap.get(n*i+j),omap.get(n*i+j+1));
                        }
                    }
                }
            }
            isConnected=true;
            ArrayList<Integer> O=g2.AP(ones);
            if(isConnected==true && O.size()!=0)
            {
                cnt++;
                int val=O.get(O.size()-1);
                X.add(val/n);
                Y.add(val%n);
            }
            System.out.println(cnt);
            for(int i=0;i<X.size();i++)
                System.out.println((X.get(i)+1)+" "+(Y.get(i)+1));
            

        }
    }
}
