<?php


/*
 * 最大フロー問題 を解くライブラリです。
 * ref. AtCoder Library
 */
class MaxFlow
{

    private int $n;
    private array $g;
    private array $pos = [];

    /**
     * MaxFlow constructor.
     * n 頂点 0 辺のグラフを作る。
     * 計算量 O(n)
     * @param int $n 0 ≤ n ≤ 10^8
     */
    function __construct(int $n)
    {
        $this->n = $n;
        $this->g = array_fill(0,$n,[]);
    }

    /**
     * fromからtoへ最大容量cap、流量 0 の辺を追加し、何番目に追加された辺かを返す。
     * 計算量 ならしO(1)
     * @param int $from 0 ≤ from < n
     * @param int $to 0 ≤ to < n
     * @param int $cap 0 ≤ cap
     * @return int 追加された辺の番号
     */
    public function add_edge(int $from, int $to, int $cap):int
    {
        assert(0 <= $from && $from < $this->n);
        assert(0 <= $to && $to < $this->n);
        assert(0 <= $cap);
        $m = count($this->pos);
        $this->pos[] = [$from, count($this->g[$from])];
        $this->g[$from][] = [$to, count($this->g[$to]), $cap];
        $this->g[$to][] = [$from, count($this->g[$from]) -1, 0];
        return $m;
    }

    /**
     * (1) 頂点 s から t へ流せる限り流し、流せた量を返す。 (第三引数なし）
     * (2) 頂点 s から t へ流量 flow_limit に達するまで流せる限り流し、流せた量を返す。
     * 複数回呼ぶことも可能で、その時の挙動は Appendix を参照してください。
     * 計算量：　mを追加された辺数として、
     * O(min(mn^(2/3),m^(2/3))) (辺の容量がすべて1)
     * O(mn^2)
     * @param int $s
     * @param int $t
     * @param int $flow_limit
     * @return int 流せた量
     */
    public function flow(int $s, int $t, int $flow_limit = PHP_INT_MAX):int
    {
        assert(0 <= $s && $s < $this->n);
        assert(0 <= $t && $t < $this->n);
        $iter = array_fill(0, $this->n, 0);
        $level = [];

        $bfs = function () use ($s, $t) {
            $level = array_fill(0, $this->n, -1);
            $level[$s] = 0;
            $que = new SplQueue();
            $que->enqueue($s);
            while (!$que->isEmpty()) {
                $v = $que->dequeue();
                foreach ($this->g[$v] as $e) {
                    if ($e[2] === 0 || $level[$e[0]] >= 0) {
                        continue;
                    }
                    $level[$e[0]] = $level[$v] + 1;
                    if ($e[0] === $t) {
                        return $level;
                    }
                    $que->enqueue($e[0]);
                }
            }
            return $level;
        };

        $dfs = function (int $v, int $up) use ($s, &$level, &$iter, &$dfs) {
            if ($v === $s) {
                return $up;
            }
            $res = 0;
            $level_v = $level[$v];
            for ($i = $iter[$v]; $i < count($this->g[$v]); $i++) {
                $e = $this->g[$v][$i];
                if ($level_v <= $level[$e[0]] || $this->g[$e[0]][$e[1]][2] === 0) {
                    continue;
                }
                $d = $dfs($e[0], min($up - $res, $this->g[$e[0]][$e[1]][2]));
                if ($d <= 0) {
                    continue;
                }
                $this->g[$v][$i][2] += $d;
                $this->g[$e[0]][$e[1]][2] -= $d;
                $res += $d;
                if ($res === $up) {
                    break;
                }
            }
            return $res;
        };
        $flow = 0;
        while ($flow < $flow_limit) {
            $level = $bfs();
            if ($level[$t] == -1) {
                break;
            }
            $iter = array_fill(0, $this->n, 0);
            while ($flow < $flow_limit) {
                $f = $dfs($t, $flow_limit - $flow);
                if (!$f) {
                    break;
                }
                $flow += $f;
            }
        }
        return $flow;
    }

    /**
     * 今の内部の辺の状態を返す
     * 計算量　O(1)
     * @param int $n 辺の番号
     * @return array [from, to, Cap, flow]
     */
    public function get_edge(int $n):array
    {
        assert(isset($this->pos[$n]));
        $e = $this->g[$this->pos[$n][0]][$this->pos[$n][1]];
        $re = $this->g[$e[0]][$e[1]];
        return [$this->pos[$n][0], $e[0], $e[2] + $re[2], $re[2]];
    }

    /**
     * 今の内部の辺の状態を返す
     * 辺の順番はadd_edgeで追加された順番と同一
     * 計算量 O(m)
     * @return array [[from, to, cap, flow], ...
     */
    public function edges():array
    {
        $result = [];
        for($i=0;$i<count($this->pos);$i++){
            $result[] = $this->get_edge($i);
        }
        return $result;
    }

    /**
     * i 番目に変更された辺の容量、流量をnew_cap, new_flowに変更する。他の辺の容量、流量は変更しない。
     * 詳細は Appendix を参照してください
     * 計算量 O(1)
     * @param int $i
     * @param int $new_cap 0 ≤ new_cap
     * @param int $new_flow 0 ≤ new_flow ≤ new_cap
     */
    public function change_edge(int $i, int $new_cap, int $new_flow){
        assert(isset($pos[$i]));
        assert(0 <= $new_flow && $new_flow <= $new_cap);
        $e = &$this->g[$pos[$i][0]][$pos[$i][1]];
        $re = &$this->g[$e[0]][$e[1]];
        $e[2] = $new_cap - $new_flow;
        $re[2] = $new_flow;

    }

    /**
     * 長さ n のvectorを返す。
     * i 番目の要素には、頂点 s から i へ残余グラフで到達可能なとき、またその時のみ true を返す。
     * flow(s, t)をflow_limitなしでちょうど一回呼んだ後に呼ぶと、返り値は s, t 間のmincutに対応します。
     * 詳細な挙動は Appendix を参照してください。
     * 計算量 O(n+m)
     * @param int $s
     * @return array
     */
    public function min_cut(int $s):array
    {
        $visited = array_fill(0,$this->n, false);
        $que = new SplQueue();
        $que->enqueue($s);
        while(!$que->isEmpty()){
            $p = $que->dequeue();
            $visited[$p] = true;
            foreach($this->g[$p] as $e){
                if($e[2] && !$visited[$e[0]]){
                    $visited[$e[0]] = true;
                    $que->enqueue($e[0]);
                }
            }
        }
        return $visited;
    }


}

[$N, $M] = fscanf(STDIN, "%d%d");

$flow = new MaxFlow($N*$M+2);

$grid = [];
$tmp = "";
for($i=0;$i<$N;$i++){
    [$tmp] = fscanf(STDIN, "%s");
    $grid[] = str_split($tmp);
}

$s = $M * $N;
$t = $M * $N + 1;

for($i=0;$i<$N;$i++){
    for($j=0;$j<$M;$j++){
        if($grid[$i][$j] !=="#"){
            if(($i + $j) % 2 === 0){
                $flow->add_edge($s, $i * $M + $j, 1);
            }else{
                $flow->add_edge($i * $M + $j, $t, 1);
            }

        }
    }
}

for($i=0;$i<$N;$i++){
    for($j=0;$j<$M;$j++){
        if(($i + $j) % 2 || $grid[$i][$j] === "#"){
            continue;
        }
        $st = $i * $M + $j;
        if($j && $grid[$i][$j-1] === "."){
            $flow->add_edge($st, $st-1, 1);
        }
        if($i && $grid[$i-1][$j] === "."){
            $flow->add_edge($st, $st - $M, 1);
        }
        if($i + 1 < $N && $grid[$i+1][$j] === "."){
            $flow->add_edge($st, $st + $M, 1);
        }
        if($j+1 < $M && $grid[$i][$j+1] === "."){
            $flow->add_edge($st, $st+1, 1);
        }
    }
}

echo $flow->flow($s, $t).PHP_EOL;

foreach($flow->edges() as $value){
    if($value[0] === $s || $value[1] === $t || !$value[3]){
        continue;
    }
    $from = [intdiv($value[0], $M), $value[0] % $M];
    $to = [intdiv($value[1], $M), $value[1] % $M];
    if(abs($value[0]- $value[1]) !== 1 || $M === 1){
        $grid[min($from[0], $to[0])][$from[1]] = "v";
        $grid[max($from[0], $to[0])][$from[1]] = "^";
    }else{
        $grid[$from[0]][min($from[1], $to[1])] = ">";
        $grid[$from[0]][max($from[1], $to[1])] = "<";

    }

}

foreach($grid as $row){
    echo implode("", $row).PHP_EOL;
}

Measured memory_bytes: 67656