Problem:
Problem D: Cliff Climbing

At 17:00, special agent Jack starts to escape from the enemy camp.
There is a cliff in between the camp and the nearest safety zone.
Jack has to climb the almost vertical cliff
by stepping his feet on the blocks that cover the cliff.
The cliff has slippery blocks where Jack has to
spend time to take each step.
He also has to bypass some blocks that are too loose to support his weight.
Your mission is to write a program that calculates the minimum time to complete climbing.

Figure D-1 shows an example of cliff data that you will
receive.
The cliff is covered with square blocks.
Jack starts cliff climbing from the ground under the cliff,
by stepping his left or right foot on one of the blocks marked with
'S' at the bottom row.
The numbers on the blocks are the "slippery levels". It takes
t time units for him to safely put his foot on a
block marked with t, where 1 ≤ t ≤ 9.
He cannot put his feet on blocks marked with 'X'.
He completes the climbing when he puts
either of his feet on one of the blocks marked with 'T' at the top row.

Figure D-1: Example of Cliff Data

Jack's movement must meet the following constraints.
After putting his left (or right) foot on a block, he can only move
his right (or left, respectively) foot.
His left foot position (lx, ly) and his right foot position
(rx, ry) should satisfy
lx < rx
and | lx - rx | + | ly - ry | ≤ 3
.
This implies that, given a position of his left foot in Figure D-2 (a), he has to
place his right foot on one of the nine blocks marked with blue color.
Similarly, given a position of his right foot in Figure D-2 (b),
he has to place his
left foot on one of the nine blocks marked with blue color.

Figure D-2: Possible Placements of Feet

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

s(1,1) ... s(1,w)

s(2,1) ... s(2,w)

...

s(h,1) ... s(h,w)

The integers w and h are the width and the height of
the matrix data of the cliff. You may assume 2 ≤ w ≤ 30 and 5 ≤ h ≤ 60.
Each of the following h lines consists of w characters
delimited by a space.
The character s(y, x) represents the state of the block at
position
(x, y) as follows:

'S': Jack can start cliff climbing from this block.

'T': Jack finishes climbing when he reaches this block.

'X': Jack cannot put his feet on this block.

'1' - '9' (= t): Jack has to spend t time units
to put either of his feet on this block.

You can assume that it takes no time to put a foot on a block marked with 'S' or 'T'.

Output

For each dataset, print a line only having a decimal integer indicating
the minimum time required for the cliff climbing,
when Jack can complete it.
Otherwise, print a line only having "-1" for the dataset.
Each line should not have any characters other than these numbers.

Sample Input

6 6
4 4 X X T T
4 7 8 2 X 7
3 X X X 1 8
1 2 X X X 6
1 1 2 4 4 7
S S 2 3 X X
2 10
T 1
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
2 10
T X
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
10 10
T T T T T T T T T T
X 2 X X X X X 3 4 X
9 8 9 X X X 2 9 X 9
7 7 X 7 3 X X 8 9 X
8 9 9 9 6 3 X 5 X 5
8 9 9 9 6 X X 5 X 5
8 6 5 4 6 8 X 5 X 5
8 9 3 9 6 8 X 5 X 5
8 3 9 9 6 X X X 5 X
S S S S S S S S S S
10 7
2 3 2 3 2 3 2 3 T T
1 2 3 2 3 2 3 2 3 2
3 2 3 2 3 2 3 2 3 4
3 2 3 2 3 2 3 2 3 5
3 2 3 1 3 2 3 2 3 5
2 2 3 2 4 2 3 2 3 5
S S 2 3 2 1 2 3 2 3
0 0

Output for the Sample Input

12
5
-1
22
12

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)]
struct Coordinate{
    x: i32, y: i32
}

impl Coordinate {
    fn manhattan_distance(&self, other: Coordinate) -> i32 {
        (self.x - other.x).abs() + (self.y - other.y).abs()
    }
}
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}
    }
}
#[derive(Copy, Clone, Debug)]
enum Block {
    Start, Goal, Break, Num(i32)
}
impl FromStr for Block {
    type Err = ();
    fn from_str(s: &str) -> std::result::Result<Self, <Self as std::str::FromStr>::Err> {
        match s {
            "S" => Ok(Block::Start),
            "T" => Ok(Block::Goal),
            "X" => Ok(Block::Break),
            _ => {
                if let Ok(n) = s.parse::<i32>() {
                    Ok(Block::Num(n))
                }else {
                    Err(())
                }
            }
        }
    }
}
impl Block {
    fn is_goal(&self) -> bool {
        match self {
            &Block::Goal => true,
            _ => false
        }
    }
    fn is_start(&self) -> bool {
        match self {
            &Block::Start => true,
            _ => false
        }
    }
}
fn find_start_pos(state: &Vec<Vec<Block>>) -> Vec<Coordinate> {
    let mut res = Vec::with_capacity(2);
    for i in 0 .. state.len() {
        for j in 0 .. state[i].len() {
            match state[i][j] {
                Block::Start => res.push(Coordinate{x: j as i32, y: i as i32}),
                _ => ()
            }
        }
    }
    res
}

fn main() {
    let right_next = (1 .. 4).flat_map(|x| (-2 .. 3).map(move |y| Coordinate{x: x, y: y})).filter(|c| c.x.abs() + c.y.abs() <= 3).collect::<Vec<_>>();
    let left_next = (-3 .. 0).flat_map(|x| (-2 .. 3).map(move |y| Coordinate{x: x, y: y})).filter(|c| c.x.abs() + c.y.abs() <= 3).collect::<Vec<_>>();
    loop {
        read!(width: usize, height: usize);
        if width == 0 && height == 0 {break;}
        read!(state: [[Block]; height]);
        let mut memo = vec![vec![vec![std::i32::MAX; width]; height]; 2];
        let mut queue = BinaryHeap::new();
        for start in find_start_pos(&state) {
            queue.push(Rev(KeyValue{key: 0, value: (0, start)}));
            queue.push(Rev(KeyValue{key: 0, value: (1, start)}));
            memo[0][start.y as usize][start.x as usize] = 0;
            memo[1][start.y as usize][start.x as usize] = 0;
        }
        let mut result = None;
        while let Some(Rev(KeyValue{key: time, value: value})) = queue.pop() {
            match value {
                (0, left) => {
                    for next_right in right_next.iter().map(|&c| c + left).filter(|c| 0 <= c.x && c.x < width as i32 && 0 <= c.y && c.y < height as i32) {
                        match state[next_right.y as usize][next_right.x as usize] {
                            Block::Num(c) => {
                                if memo[1][next_right.y as usize][next_right.x as usize] > time + c {
                                    memo[1][next_right.y as usize][next_right.x as usize] = time + c;
                                    queue.push(Rev(KeyValue{key: time + c, value: (1, next_right)}));
                                }
                            }
                            Block::Break => (),
                            Block::Goal => {
                                result = Some(time);
                                break;
                            }
                            _ => {
                                if memo[1][next_right.y as usize][next_right.x as usize] > time {
                                    memo[1][next_right.y as usize][next_right.x as usize] = time;
                                    queue.push(Rev(KeyValue{key: time, value: (1, next_right)}));
                                }
                            }
                        }
                    }
                },
                (1, right) => {
                    for next_left in left_next.iter().map(|&c| c + right).filter(|c| 0 <= c.x && c.x < width as i32 && 0 <= c.y && c.y < height as i32) {
                        match state[next_left.y as usize][next_left.x as usize] {
                            Block::Num(c) => {
                                if memo[0][next_left.y as usize][next_left.x as usize] > time + c {
                                    memo[0][next_left.y as usize][next_left.x as usize] = time + c;
                                    queue.push(Rev(KeyValue{key: time + c, value: (0, next_left)}));
                                }
                            }
                            Block::Break => (),
                            Block::Goal => {
                                result = Some(time);
                                break;
                            }
                            _ => {
                                if memo[0][next_left.y as usize][next_left.x as usize] > time {
                                    memo[0][next_left.y as usize][next_left.x as usize] = time;
                                    queue.push(Rev(KeyValue{key: time, value: (0, next_left)}));
                                }
                            }
                        }
                    }
                },
                _ => panic!()
            }
            if result.is_some() {break;}
        }
        println!("{}", result.unwrap_or(-1));
    }
}