#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
using namespace std;

#pragma region Macros
using ll = long long;
#define int ll
using pii = pair<int, int>;
using tiii = tuple<int, int, int>;
template<class T = ll> using V = vector<T>;
template<class T = ll> using VV = V<V<T>>;
#define IOS\
    ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);
#define FOR(i,l,r) for(ll i=(l);i<(r);++i)
#define REP(i,n) FOR(i,0,n)
#define REPS(i,n) FOR(i,1,n+1)
#define RFOR(i,l,r) for(ll i=(l);i>=(r);--i)
#define RREP(i,n) RFOR(i,n-1,0)
#define RREPS(i,n) RFOR(i,n,1)
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(),(x).end()
#define SORT(name) sort(name.begin(), name.end())
#define RSORT(name)\
    SORT(name);\
    reverse(all(name));
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
inline void Yes(bool b = true) {cout << (b ? "Yes" : "No") << '\n';}
inline void YES(bool b = true) {cout << (b ? "YES" : "NO") << '\n';}
template <class T> inline void print(T x){ cout << x << '\n';}
template<typename T1,typename T2> inline void chmin(T1 &a, T2 b){ if(a > b) a = b; }
template<typename T1,typename T2> inline void chmax(T1 &a, T2 b){ if(a < b) a = b; }

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
#pragma endregion

#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

// 二次元配列の各インデックスに一意の id を振ります
class PosId2D {
    public:
        PosId2D() : m_H(0), m_W(0) {}
        PosId2D(ll h, ll w) : m_H(0), m_W(0) { Init(h, w); }
        void Init(ll h, ll w) { m_H = h; m_W = w; }

        // id からそれに対応する (i, j) を返します
        pair<ll, ll> GetPos(ll id) {
            assert(m_H > 0 && m_W > 0);
            return make_pair(id / m_W, id % m_W);
        }
        // i, j からそれに対応する id を返します
        ll GetId(ll i, ll j) {
            return i * m_W + j;
        }
        ll GetId(pair<ll, ll> pos) { return GetId(pos.first, pos.second); }

        // 二次元グリッド上に存在しない特別な id を返します
        // n: 何番目の特別な id か（特別な id が複数作れるように渡す）
        ll GetSpecial(ll n) { return m_H * m_W + n; }

    private:
        ll m_H; // 高さ
        ll m_W; // 幅
};

const int MOD = 1000000007;
const int MAX_N = 100010;

signed main() {
    IOS;

    int N, M;
    cin >> N >> M;
    V<string> S(N);
    REP(i, N) {
        cin >> S[i];
    }

    PosId2D pi(N, M);

    // s, t を用意し
    // (0,0) からマンハッタン距離が偶数のものへ s から辺を張る
    // 同様にマンハッタン距離が奇数のものから t へ辺を張る
    mf_graph<int> graph(N * M + 10);
    int node_s = pi.GetSpecial(1);
    int node_t = pi.GetSpecial(2);
    REP(i, N) {
        REP(j, M) {
            if(S[i][j] == '#') { continue; }
            if((i + j) % 2 == 0) {
                graph.add_edge(node_s, pi.GetId(i, j), 1);
            }
            else {
                graph.add_edge(pi.GetId(i, j), node_t, 1);
            }
        }
    }

    // 偶数から奇数へ容量 1 の辺を張る
    REP(i, N) {
        REP(j, M) {
            if(S[i][j] == '#') { continue; }
            if((i + j) % 2 == 0) {
                // 上下左右へ辺を張る
                if(i > 0 && S[i - 1][j] == '.') {
                    graph.add_edge(pi.GetId(i, j), pi.GetId(i - 1, j), 1);
                }
                if(i < N - 1 && S[i + 1][j] == '.') {
                    graph.add_edge(pi.GetId(i, j), pi.GetId(i + 1, j), 1);
                }
                if(j > 0 && S[i][j - 1] == '.') {
                    graph.add_edge(pi.GetId(i, j), pi.GetId(i, j - 1), 1);
                }
                if(j < M - 1 && S[i][j + 1] == '.') {
                    graph.add_edge(pi.GetId(i, j), pi.GetId(i, j + 1), 1);
                }
            }
        }
    }

    int ans = graph.flow(node_s, node_t);
    print(ans);

    // 内部の状態を取得
    auto edges = graph.edges();
    for(auto e : edges) {
        if(e.flow == 0) { continue; }
        if(e.to == node_s || e.to == node_t || e.from == node_s || e.from == node_t) { continue; }
        int f_i = pi.GetPos(e.from).first;
        int f_j = pi.GetPos(e.from).second;
        int t_i = pi.GetPos(e.to).first;
        int t_j = pi.GetPos(e.to).second;
        // to が from の上下左右のどこにあたるか確認
        if(f_i - 1 == t_i) {
            S[f_i][f_j] = '^'; S[t_i][t_j] = 'v';
        }
        if(f_i + 1 == t_i) {
            S[f_i][f_j] = 'v'; S[t_i][t_j] = '^';
        }
        if(f_j - 1 == t_j) {
            S[f_i][f_j] = '<'; S[t_i][t_j] = '>';
        }
        if(f_j + 1 == t_j) {
            S[f_i][f_j] = '>'; S[t_i][t_j] = '<';
        }
    }

    REP(i, N) {
        print(S[i]);
    }

    return 0;
}


Measured memory_bytes: 6232