use std::ops::DivAssign;
use std::ops::MulAssign;
use std::ops::SubAssign;
use std::collections::BinaryHeap;
use std::str::FromStr;
use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::{HashMap, BTreeSet};
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer.trim().to_owned()
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split_whitespace().map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_map {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
#[derive(Copy, Clone)]
struct Position {
    x: i32, y: i32
}
impl Position {
    fn to_index(&self) -> usize {
        (self.x + (self.y << 2)) as usize
    }
    fn neighbor(&self) -> Vec<Position> {
        vec![
            Position{x: -1, y: -1}, Position{x: 0, y: -1}, Position{x: 1, y: - 1},
            Position{x: -1, y: 0}, Position{x: 1, y: 0},
            Position{x: -1, y: 1}, Position{x: 0, y: 1}, Position{x: 1, y: 1}
        ].into_iter().map(|d| self.add(d)).filter(|p| 0 <= p.x && p.x < 4 && 0 <= p.y && p.y < 5).collect()
    }
    fn add(&self, other: Position) -> Position {
        Position{x: self.x + other.x, y: self.y + other.y}
    }
}
fn dfs(usage: usize, indices: &mut Vec<usize>, card_type: &Vec<usize>, memo: &mut HashMap<usize, usize>, neighbors: &Vec<Vec<usize>>) -> usize {
    if let Some(&r) = memo.get(&usage) {
        return r
    }
    let mut result = indices.len();
    for current in 0 .. indices.len() {
        for &neighbor in &neighbors[current] {
            if neighbor >= indices.len() {break;}
            if card_type[indices[current]] != card_type[indices[neighbor]] {continue;}
            let l = min(current, neighbor);
            let r = max(current, neighbor);
            let next_usage = usage | (1 << indices[current]) | (1 << indices[neighbor]);
            let r_card = indices.remove(r);
            let l_card = indices.remove(l);
            result = min(result, dfs(next_usage, indices, card_type, memo, neighbors));
            indices.insert(l, l_card);
            indices.insert(r, r_card);
        }
    }
    memo.insert(usage, result);
    result
}
fn main() {
    let neighbors = (0 .. 5).into_iter().flat_map(|y| (0 .. 4).into_iter().map(move |x| Position{x: x, y: y}.neighbor().into_iter().map(|p| p.to_index()).collect::<Vec<_>>())).collect::<Vec<_>>();
    let mut indices = (0 .. 20).collect::<Vec<_>>();
    read!(n: usize);
    for _ in 0 .. n {
        read_map!(input: [{
            read!(line: [usize]);
            line
        }; 5]);
        let cards = input.into_iter().flat_map(|x| x).collect::<Vec<_>>();
        let mut memo = HashMap::new();
        println!("{}", dfs(0, &mut indices, &cards, &mut memo, &neighbors));
    }
}


Measured memory_bytes: 5064