import java.io.*;
import java.util.*;

/* Sample Solution to C -- Taxi Cab scheme / Mikael Goldmann
 * Based on matching. Find largest possible matching of ends of trips
 * to beginnings of other trips.
 *
 * The answer is exactly the number of unmatched end of trips
 *
 * Start by greedily chosing a maximal matching rather 
 *  than starting from scratch. 
 */

class Trip 
{
    int x1;
    int x2;
    int y1;
    int y2;
    int time;
    
    Trip(int a1, int b1, int a2, int b2, int t) 
    {
	x1=a1;
	y1=b1;
	x2=a2;
	y2=b2;
	time=t;
    }
}

	
class taxi_mg 
{
    static BufferedReader stdin =
	new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter stdout =
	new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    int [] vis;
    
    public static void main(String[] s)   throws Exception
    {
	(new taxi_mg()).run();
	stdout.close();	
    }
    

    void run() throws Exception
    {
	int N = Integer.parseInt(stdin.readLine());
	for (int i = 1; i <= N; ++i) solve(i);
    }
    

    void solve(int num) throws Exception
    {
	int N = Integer.parseInt(stdin.readLine());
	Trip[] trip = new Trip[N];

	String s1;	
	StringTokenizer st1;	
	int i,j;
	for (i=0; i < N; ++i) {
	    s1 = stdin.readLine();
	    st1 = new StringTokenizer(s1);
	    s1 = st1.nextToken(); // time to start
	    int x1 = Integer.parseInt(st1.nextToken());
	    int y1 = Integer.parseInt(st1.nextToken());
	    int x2 = Integer.parseInt(st1.nextToken());
	    int y2 = Integer.parseInt(st1.nextToken());
	    st1 = new StringTokenizer(s1, ":");
	    int time = Integer.parseInt(st1.nextToken());
	    time *= 60;
	    time += Integer.parseInt(st1.nextToken());
	    trip[i] = new Trip(x1, y1, x2, y2, time);
	}
	
	boolean[] vmatched  = new boolean[2*N];
	int[][] adj = new int[2*N][2*N];


	for(i=0; i < N; ++i)
	    for (j=0; j < N; ++j) {
		int x1 = trip[i].x1;
		int y1 = trip[i].y1;
		
		int x2 = trip[i].x2;
		int y2 = trip[i].y2;
		
		int x3 = trip[j].x1;
		int y3 = trip[j].y1;
		
		int t1 = trip[i].time + Math.abs(x1-x2) + Math.abs(y1-y2);
		
		t1 += Math.abs(x2-x3) + Math.abs(y2-y3);
		if (t1 < trip[j].time) {
		    adj[i][j+N] = adj[j+N][i] = 1;
		    if (!vmatched[i] && !vmatched[j+N]) {
			adj[i][j+N] = adj[j+N][i] = -1;
			vmatched[i] = vmatched[j+N] = true;
		    }
		    
		}
	    }

	int[] vis = new int[2*N];
	int cookie = 1;
	
	
	while (improve(N, vmatched, adj, cookie, vis)) 
	    ++cookie;
	
	int sum = 0;
	for (i=N; i < 2*N; ++i) 
	    if (!vmatched[i]) ++sum;
	stdout.println(sum);
    }
	    

    boolean improve(int N, 
		    boolean[] vm, int[][] a, 
		    int cookie, int[] vis)
    {
	for (int i = 0; i < N; ++i)
	    if (!vm[i] && vis[i] != cookie 
		&& dfs(i,i, N, vm, a, cookie, vis, 1)) 
		return true;
	return false;
    }

    boolean dfs(int s, int u, int N, boolean[] vm,
	    int[][] adj, int cookie, int[] vis, int match) 
    {
	vis[u] = cookie;	
	if (!vm[u] && u != s) { // found path! 
	    vm[u] = true;
	    return true;
	}
	int lo = (u >= N) ? 0 : N;
	int hi = (u >= N) ? N : 2*N;
	lo = 0;
	hi = 2*N;
	for (int i=lo; i < hi; ++i) {
	    if (adj[u][i] == match && vis[i] != cookie) {
		if(dfs(s, i, N, vm, adj, cookie, vis, -match)) { // found path
		    vm[u] = true;
		    adj[u][i] = adj[i][u] = -match;
		    return true;
		}
	    }
	}
	return false;
		
    }
    
}

	
	    
		
	
