#ifdef LOCAL
//#define _GLIBCXX_DEBUG
#endif
//#pragma GCC target("avx512f,avx512dq,avx512cd,avx512bw,avx512vl")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<int, int> Pi;
typedef vector<ll> Vec;
typedef vector<int> Vi;
typedef vector<string> Vs;
typedef vector<char> Vc;
typedef vector<P> VP;
typedef vector<vector<ll>> VV;
typedef vector<vector<int>> VVi;
typedef vector<vector<char>> VVc;
typedef vector<vector<vector<ll>>> VVV;
typedef vector<vector<vector<vector<ll>>>> VVVV;

#define REP(i, a, b) for(ll i=(a); i<(b); i++)
#define PER(i, a, b) for(ll i=(a); i>=(b); i--)
#define rep(i, n) REP(i, 0, n)
#define per(i, n) PER(i, n, 0)
const ll INF = 1e18+18;
const ll MOD = 1000000007;
#define Yes(n) cout << ((n) ? "Yes" : "No") << endl;
#define YES(n) cout << ((n) ? "YES" : "NO") << endl;
#define ALL(v) v.begin(), v.end()
#define rALL(v) v.rbegin(), v.rend()
#define pb(x) push_back(x)
#define mp(a, b) make_pair(a,b)
#define Each(a, b) for(auto &a :b)
#define rEach(i, mp) for (auto i = mp.rbegin(); i != mp.rend(); ++i)
#ifdef LOCAL
#define dbg(x_) cerr << #x_ << ":" << x_ << endl;
#define dbgmap(mp) cerr << #mp << ":"<<endl; for (auto i = mp.begin(); i != mp.end(); ++i) { cerr << i->first <<":"<<i->second << endl;}
#define dbgset(st) cerr << #st << ":"<<endl; for (auto i = st.begin(); i != st.end(); ++i) { cerr << *i <<" ";}cerr<<endl;
#define dbgarr(n, m, arr) rep(i,n){rep(j,m){cerr<<arr[i][j]<<" ";}cerr<<endl;}
#define dbgdp(n, arr) rep(i,n){cerr<<arr[i]<<" ";}cerr<<endl;
#else
#define dbg(...)
#define dbgmap(...)
#define dbgset(...)
#define dbgarr(...)
#define dbgdp(...)
#endif
#define out(a) cout<<a<<endl
#define out2(a, b) cout<<a<<" "<<b<<endl
#define vout(v) rep(i,v.size()){cout<<v[i]<<" ";}cout<<endl
#define Uniq(v) v.erase(unique(v.begin(), v.end()), v.end())
#define fi first
#define se second

template<class T>
bool chmax(T &a, const T &b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool chmin(T &a, const T &b) {
    if(b < a) {
        a = b;
        return true;
    }
    return false;
}

template<typename T1, typename T2>
ostream &operator<<(ostream &s, const pair<T1, T2> &p) { return s<<"("<<p.first<<", "<<p.second<<")"; }

template<typename T>
istream &operator>>(istream &i, vector<T> &v) {
    rep(j, v.size())i>>v[j];
    return i;
}

// vector
template<typename T>
ostream &operator<<(ostream &s, const vector<T> &v) {
    int len = v.size();
    for(int i = 0; i < len; ++i) {
        s<<v[i];
        if(i < len-1) s<<"	";
    }
    return s;
}

// 2 dimentional vector
template<typename T>
ostream &operator<<(ostream &s, const vector<vector<T> > &vv) {
    int len = vv.size();
    for(int i = 0; i < len; ++i) {
        s<<vv[i]<<endl;
    }
    return s;
}

template<class Cap>
struct mf_graph {
    template<class T>
    struct simple_queue {
        std::vector<T> payload;
        int pos = 0;
        void reserve(int n) { payload.reserve(n); }
        int size() const { return int(payload.size())-pos; }
        bool empty() const { return pos == int(payload.size()); }
        void push(const T &t) { payload.push_back(t); }
        T &front() { return payload[pos]; }
        void clear() {
            payload.clear();
            pos = 0;
        }
        void pop() { pos++; }
    };
public:
    mf_graph() : _n(0) {}
    mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        g[from].push_back(_edge{to, int(g[to].size()), cap});
        g[to].push_back(_edge{from, int(g[from].size())-1, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap+_re.cap, _re.cap};
    }

    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for(int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }

    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto &_e = g[pos[i].first][pos[i].second];
        auto &_re = g[_e.to][_e.rev];
        _e.cap = new_cap-new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }

    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        std::vector<int> level(_n), iter(_n);
        simple_queue<int> que;
        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for(auto e : g[v]) {
                    if(e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v]+1;
                    if(e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if(v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for(int &i = iter[v]; i < int(g[v].size()); i++) {
                _edge &e = g[v][i];
                if(level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                        self(self, e.to, std::min(up-res, g[e.to][e.rev].cap));
                if(d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if(res == up) break;
            }
            return res;
        };
        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if(level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(dfs, t, flow_limit-flow);
                if(!f) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for(auto e : g[p]) {
                if(e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

int solve() {
    ll h,w;
    cin>>h>>w;

//    VVc grid(h, Vc(w));
//    rep(i,h){
//        string s;
//        cin>>s;
//        rep(j,w){
//            grid[i][j] = s[j];
//        }
//    }
    Vs grid(h);
    cin>>grid;

    /**
     * generate (s -> even grid -> odd grid -> t) graph
     * grid(i, j) correspond to vertex (i * m + j)
     **/
    mf_graph<ll> g(h * w + 2);
    ll s = h*w, t = h*w + 1;

    // s -> even / odd -> t
    auto idx = [&](ll y, ll x) { return y*w+x; };
    rep(i,h){
        rep(j,w){
            if (grid[i][j] == '#') continue;
            int v = idx(i,j);
            if ((i + j) % 2 == 0) {
                g.add_edge(s, v, 1);
            } else {
                g.add_edge(v, t, 1);
            }
        }
    }

    Vec dy = {0,1,0,-1,1,1,-1,-1};
    Vec dx = {1,0,-1,0,1,-1,1,-1};
    auto in = [&](ll y, ll x) {
        return y >= 0 && y < h && x >= 0 && x < w;
    };
    // even -> odd
    rep(i,h){
        rep(j,w) {
            if ((i + j) % 2 == 1 || grid[i][j] == '#') continue;
            ll vf = idx(i,j);
            rep(k,4){
                ll ny = i+dy[k];
                ll nx = j+dx[k];
                if(!in(ny,nx))continue;
                ll vt = idx(ny,nx);
                g.add_edge(vf,vt,1);
            }
        }
    }

    cout << g.flow(s, t) << endl;
    auto edges = g.edges();

    for (auto e : edges) {
        if (e.from == s || e.to == t || e.flow == 0) continue;
        Vec v = {e.from, e.to, e.flow};
        ll uy = e.from/w, ux = e.from%w;
        ll vy = e.to/w, vx = e.to%w;
        Vec ev = {uy,ux,vy,vx};
        ll dir = -1;
        rep(k,4){
            ll ny = uy+dy[k];
            ll nx = ux+dx[k];
            if(ny==vy && nx==vx){
                dir = k;
            }
        }
        if(dir==0){
            grid[uy][ux] = '>';
            grid[vy][vx] = '<';
        }
        if(dir==1){
            grid[uy][ux] = 'v';
            grid[vy][vx] = '^';
        }
        if(dir==2){
            grid[uy][ux] = '<';
            grid[vy][vx] = '>';
        }
        if(dir==3){
            grid[uy][ux] = '^';
            grid[vy][vx] = 'v';
        }
    }

    rep(i,h){
        cout << grid[i] << endl;
    }

    return 0;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<std::setprecision(10);
//    ll T;
//    cin>>T;
//    while(T--)
    solve();
}


Measured memory_bytes: 6236