#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

#include <atcoder/dsu.hpp>
#include <atcoder/fenwicktree.hpp>
#include <atcoder/segtree.hpp>
#include <atcoder/lazysegtree.hpp>
#include <atcoder/maxflow.hpp>

using namespace std;
using namespace atcoder;

////////////////	型名など
typedef long long ll;
#define endl '\n'

////////////////	各種定数
const ll INF = 1LL << 60;
const double EPS = 1e-12;

////////////////	便利なテンプレート関数
template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

////////////////	UnionFind
#define UnionFind dsu

////////////////	平面から直線への写像
template<typename T> struct HashMap2D {
	HashMap2D() {
		Hmax = 1000000007, Hmin = -1000000007;
		Wmax = 1000000007, Wmin = -1000000007;
		Height = Hmax - Hmin;
		Width = Wmax - Wmin;
	}
	HashMap2D(T H_max, T W_max, T H_min = 0, T W_min = 0) {
		Hmax = H_max; Hmin = H_min;
		Wmax = W_max; Wmin = W_min;
		Height = Hmax - Hmin;
		Width = Wmax - Wmin;
	}
	T hash(T h, T w) {
		h -= Hmin, w -= Wmin;
		return Width * h + w;
	}
	pair<T, T> inv(T index) {
		pair<T, T> p;
		p.first = index / Width;
		p.second = index % Width;
		p.first += Hmin;
		p.second += Wmin;
		return p;
	}
	
private:
	T Hmax, Hmin, Wmax, Wmin;
	T Height, Width;
};

int main() {
	ios::sync_with_stdio(false);
	std::cin.tie(0);

	int N, M; cin >> N >> M;
	vector<string> S(N);
	HashMap2D<int> hm(N, M);
	for (int i = 0; i < N; i++) {
		cin >> S[i];
	}


	mf_graph<int> G(N * M + 2);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if ((i + j) % 2 == 0) {
				G.add_edge(N * M, hm.hash(i, j), 1);
			}
			else {
				G.add_edge(hm.hash(i, j), N * M + 1, 1);
			}
		}
	}
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M - 1; j++) {
			if (S[i][j] == '#' || S[i][j + 1] == '#') { continue; }
			if ((i + j) % 2 == 0) {
				G.add_edge(hm.hash(i, j), hm.hash(i, j + 1), 1);
			}
			else {
				G.add_edge(hm.hash(i, j + 1), hm.hash(i, j), 1);
			}
		}
	}
	for (int i = 0; i < N - 1; i++) {
		for (int j = 0; j < M; j++) {
			if (S[i][j] == '#' || S[i + 1][j] == '#') { continue; }
			if ((i + j) % 2 == 0) {
				G.add_edge(hm.hash(i, j), hm.hash(i + 1, j), 1);
			}
			else {
				G.add_edge(hm.hash(i + 1, j), hm.hash(i, j), 1);
			}
		}
	}

	cout << G.flow(N * M, N * M + 1) << endl;

	auto e = G.edges();

	for (int i = 0; i < e.size(); i++) {
		if (e[i].flow == 1 && e[i].from < N * M && e[i].to < N * M) {
			pair<int, int> p0 = hm.inv(e[i].from), p1 = hm.inv(e[i].to);
			if (p0.first < p1.first) { S[p0.first][p0.second] = 'v', S[p1.first][p1.second] = '^'; }
			if (p0.first > p1.first) { S[p0.first][p0.second] = '^', S[p1.first][p1.second] = 'v'; }
			if (p0.second < p1.second) { S[p0.first][p0.second] = '>', S[p1.first][p1.second] = '<'; }
			if (p0.second > p1.second) { S[p0.first][p0.second] = '<', S[p1.first][p1.second] = '>'; }
		}
	}

	for (int i = 0; i < N; i++) {
		cout << S[i] << endl;;
	}

	return 0;
}

Measured memory_bytes: 5604