Problem:
Problem F: ICPC: Intelligent Congruent Partition of Chocolate

The twins named Tatsuya and Kazuya love chocolate.
They have found a bar of their favorite chocolate in a very strange shape.
The chocolate bar looks to have been eaten partially by Mam.
They, of course, claim to eat it and then
will cut it into two pieces for their portions.
Since they want to be sure that the chocolate bar is fairly divided,
they demand that the shapes of the two pieces are congruent
and that each piece is connected.

The chocolate bar consists of many square shaped blocks of chocolate
connected to the adjacent square blocks of chocolate at their edges.
The whole chocolate bar is also connected.

Cutting the chocolate bar along with some edges of square blocks,
you should help them to divide it into two congruent and connected pieces of
chocolate. That is, one piece fits into the other
after it is rotated, turned over and moved properly.

Figure F-1: A partially eaten chocolate bar with 18 square blocks of chocolate

For example, there is a partially eaten chocolate bar
with 18 square blocks of chocolate as depicted in Figure F-1.
Cutting it along with some edges of square blocks,
you get two pieces of chocolate
with 9 square blocks each as depicted in Figure F-2.

Figure F-2: Partitioning of the chocolate bar in Figure F-1

You get two congruent and connected pieces as the result.
One of them consists of 9 square blocks hatched with horizontal lines
and the other with vertical lines.
Rotated clockwise with a right angle and turned over on a horizontal line,
the upper piece exactly fits into the lower piece.

Figure F-3: A shape that cannot be partitioned
into two congruent and connected pieces

Two square blocks touching only at their corners
are regarded as they are not connected to each other.
Figure F-3 is an example shape that cannot be partitioned into
two congruent and connected pieces.
Note that, without the connectivity requirement,
this shape can be partitioned into two congruent pieces
with three squares (Figure F-4).

Figure F-4: Two congruent but disconnected pieces

Your job is to write a program that judges whether a given bar
of chocolate can be partitioned into such two
congruent and connected pieces or not.

Input

The input is a sequence of datasets.
The end of the input is indicated by
a line containing two zeros separated by a space.
Each dataset is formatted as follows.

w h

r(1, 1) ... r(1, w)

r(2, 1) ... r(2, w)

...

r(h, 1) ... r(h, w)

The integers w and h are the width and the height of
a chocolate bar, respectively.
You may assume 2 ≤ w ≤ 10 and 2 ≤
h ≤ 10.
Each of the following h lines consists of w digits
delimited by a space.
The digit r(i, j) represents the existence of a square block of
chocolate at the position
(i, j) as follows.

'0': There is no chocolate (i.e., already eaten).

'1': There is a square block of chocolate.

You can assume that there are at most 36 square blocks of
chocolate in the bar, i.e.,
the number of digit '1's representing square blocks of chocolate
is at most 36 in each dataset.
You can also assume that there is at least one square block of chocolate in
each row and each column.

You can assume that the chocolate bar is connected.
Since Mam does not eat chocolate bars making holes in them,
you can assume that there is no dataset that represents
a bar in a shape with hole(s) as depicted in Figure F-5.

Figure F-5: A partially eaten chocolate bar with a hole
(You can assume that there is no dataset like this example)

Output

For each dataset, output a line containing one of two uppercase character
strings "YES" or "NO".
"YES" means the chocolate bar indicated by the dataset can be
partitioned into two congruent and connected
pieces, and "NO" means it cannot be partitioned into such
two pieces.
No other characters should be on the output line.

Sample Input

2 2
1 1
1 1
3 3
0 1 0
1 1 0
1 1 1
4 6
1 1 1 0
1 1 1 1
1 1 1 0
1 1 1 0
0 1 1 0
1 1 1 0
7 5
0 0 1 0 0 1 1
0 1 1 1 1 1 0
0 1 1 1 1 1 0
1 1 1 1 1 1 0
1 0 0 0 1 1 0
9 7
0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0
1 1 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 0
0 1 1 1 1 1 1 1 1
0 0 0 1 1 0 0 0 0
0 0 0 1 0 0 0 0 0
9 7
0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
0 0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0 0
7 6
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 0
1 1 1 1 1 1 0
0 1 1 1 1 1 0
0 1 1 1 1 1 0
10 10
0 1 1 1 1 1 1 1 1 1
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 1 0
1 1 1 1 1 1 1 1 1 0
0 0

Output for the Sample Input

YES
NO
YES
YES
YES
NO
NO
YES

Solution in Rust (judge verdict: Accepted)

use std::hash::Hash;
use std::collections::hash_set::Iter;
use std::rc::Rc;
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: String) => {
        let mut $ident = read_value::<String>();
    };
    ($ident: ident: String) => {
        let $ident = read_value::<String>();
    };
    (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(Eq, PartialEq)]
struct Rev<T: Ord>(T);
impl <T: std::cmp::Ord> PartialOrd for Rev<T> {
    fn partial_cmp(&self, rhs: &Rev<T>) -> std::option::Option<std::cmp::Ordering> { 
        rhs.0.partial_cmp(&self.0)
    }
}
impl <T: Ord> Ord for Rev<T> {
    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering { 
        rhs.0.cmp(&self.0)
    }
}
#[derive(Copy, Clone, Debug)]
enum Dir {
    Up, Right, Down, Left
}
impl Dir {
    fn all() -> Vec<Dir> {
        vec![Dir::Up, Dir::Right, Dir::Down, Dir::Left]
    }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Coordinate {
    x: i32, y: i32
}
impl Coordinate {
    fn rotate(&self, dir: Dir, mirror: bool) -> Coordinate {
        if mirror {
            Coordinate{x: -self.x, y: self.y}.rotate(dir, false)
        }else {
            match dir {
                Dir::Up => *self,
                Dir::Right => Coordinate{x: self.y, y: -self.x},
                Dir::Down => Coordinate{x: -self.x, y: - self.y},
                Dir::Left => Coordinate{x: -self.y, y: self.x}
            }
        }
    }
    fn neighbor(&self) -> Vec<Coordinate> {
        vec![Coordinate{x: self.x + 1, y: self.y}, Coordinate{x: self.x - 1, y: self.y}, Coordinate{x: self.x, y: self.y + 1}, Coordinate{x: self.x, y: self.y - 1}]
    }
}
impl Sub for Coordinate {
    type Output = Coordinate;
    fn sub(self, rhs: Coordinate) -> <Self as std::ops::Sub<Coordinate>>::Output {
        Coordinate{x: self.x - rhs.x, y: self.y - rhs.y}
    }
}
impl Add for Coordinate {
    type Output = Coordinate;
    fn add(self, rhs: Coordinate) -> <Self as std::ops::Add<Coordinate>>::Output {
        Coordinate{x: self.x + rhs.x, y: self.y + rhs.y}
    }
}
fn connect_count(a: Coordinate, state: &Vec<Vec<i32>>) -> usize {
    let mut stack = vec![a];
    let mut searched = vec![vec![false; state[0].len()]; state.len()];
    searched[a.y as usize][a.x as usize] = true;
    let mut count = 1;
    let color = state[a.y as usize][a.x as usize];
    while let Some(current) = stack.pop() {
        for next in current.neighbor() {
            if 0 <= next.y && next.y < state.len() as i32 && 0 <= next.x && next.x < state[next.y as usize].len() as i32 && state[next.y as usize][next.x as usize] == color && !searched[next.y as usize][next.x as usize] {
                searched[next.y as usize][next.x as usize] = true;
                stack.push(next);
                count += 1;
            }
        }
    }
    count
}
fn can_separate(a: Coordinate, b: Coordinate, dir: Dir, state: &Vec<Vec<usize>>, mirror: bool) -> bool {
    let mut a_to_b = vec![vec![None; state[0].len()]; state.len()];
    let mut b_to_a = vec![vec![None; state[0].len()]; state.len()];
    let mut coordinates = vec![];
    for i in 0 .. state.len() {
        for j in 0 .. state[i].len() {
            if state[i][j] == 0 {continue;}
            let pos = Coordinate{x: j as i32, y: i as i32};
            coordinates.push(pos);
            let a_diff = pos - a;
            let pair_pos = b + a_diff.rotate(dir, mirror);
            if 0 <= pair_pos.y && pair_pos.y < state.len() as i32 && 0 <= pair_pos.x && pair_pos.x < state[pair_pos.y as usize].len() as i32 && state[pair_pos.y as usize][pair_pos.x as usize] != 0 {
                a_to_b[i][j] = Some(pair_pos);
                b_to_a[pair_pos.y as usize][pair_pos.x as usize] = Some(pos);
            }
        }
    }
    //println!("dir: {:?}, mirror: {}\nA to B: {:?}\nB to A: {:?}", dir, mirror, a_to_b, b_to_a);
    for i in 0 .. state.len() {
        for j in 0 .. state[i].len() {
            if state[i][j] != 0 && a_to_b[i][j].is_none() && b_to_a[i][j].is_none() {
                return false;
            }
        }
    }
    if coordinates.len() & 1 != 0 {return false;}
    for mut pattern in 0 .. (1 << (coordinates.len() >> 1)) {
        let mut separate = vec![vec![0; state[0].len()]; state.len()];
        let mut can = true;
        for i in 0 .. coordinates.len() {
            if separate[coordinates[i].y as usize][coordinates[i].x as usize] == 0 {
                let y = coordinates[i].y as usize;
                let x = coordinates[i].x as usize;
                if pattern & 1 == 0 {
                    if let Some(op) = a_to_b[y][x] {
                        separate[y][x] = 1;
                        separate[op.y as usize][op.x as usize] = 2;
                    }else {
                        can = false;
                        break;
                    }
                }else {
                    if let Some(op) = b_to_a[y][x] {
                        separate[y][x] = 2;
                        separate[op.y as usize][op.x as usize] = 1;
                    }else {
                        can = false;
                        break;
                    }
                }
                pattern >>= 1;
            }
        }
        if !can {continue;}
        for c in &coordinates {
            if let Some(op) = a_to_b[c.y as usize][c.x as usize] {
                if separate[c.y as usize][c.x as usize] == separate[op.y as usize][op.x as usize] {
                    can = false;
                    break;
                }
            }
        }
        if !can {continue;}
        if connect_count(coordinates[0], &separate) << 1 == coordinates.len() {
            return true;
        }
    }
    false
}

fn main() {
    loop {
        read!(width: usize, height: usize);
        if width == 0 && height == 0 {break;}
        read!(state:[[usize]; height]);
        let mut can = false;
        let base = (0 .. height).flat_map(|y| (0 .. width).find(|&x| state[y][x] == 1).map(|x| Coordinate{x: x as i32, y: y as i32})).next().unwrap();
        for i in 0 .. height {
            for j in 0 .. width {
                //println!("i: {}, j: {}", i, j);
                if state[i][j] != 0 && (base.y != i as i32 || base.x != j as i32) {
                    if Dir::all().into_iter().any(|d| can_separate(base, Coordinate{x: j as i32, y: i as i32}, d, &state, true) || can_separate(base, Coordinate{x: j as i32, y: i as i32}, d, &state, false)) {
                        can = true;
                        break;
                    }
                }
            }
        }
        if can {
            println!("YES");
        }else {
            println!("NO");
        }
    }
}