#include <iostream>
#include <string>
#include <queue>
using namespace std;
typedef pair<int, int> P;

const int INF = 100000000;

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

char d[4] = {'v', '>', '^', '<'};

template <typename T>
struct Edge
{
    int to;
    T cap;
    int rev;
    int id;
};

template <typename T>
struct Flow
{
    int n;
    vector<int> d;
    vector<int> nx;
    vector<vector<Edge<T>>> g;
    
    Flow(){}
    
    Flow(int n) : n(n){
        d.resize(n);
        nx.resize(n);
        g.resize(n);
    }
    
    void add_edge(int from, int to, T cap, int id = -1){
        g[from].push_back((Edge<T>){to, cap, (int)g[to].size(), id});
        g[to].push_back((Edge<T>){from, 0, (int)g[from].size() - 1, -1});
    }
    
    void bfs(int r){
        fill(d.begin(), d.end(), n);
        queue<int> que;
        d[r] = 0;
        que.push(r);
        while(que.size()){
            int u = que.front();
            que.pop();
            for(Edge<T> e : g[u]){
                int v = e.to;
                if(e.cap > 0 && d[v] == n){
                    d[v] = d[u] + 1;
                    que.push(v);
                }
            }
        }
    }
    
    T dfs(int u, int s, T f){
        if(u == s) return f;
        for(int &i = nx[u]; i < (int)g[u].size(); i++){
            Edge<T> &e = g[u][i];
            int v = e.to;
            if(d[v] <= d[u] || e.cap == 0) continue;
            T fl = dfs(v, s, min(f, e.cap));
            if(fl > 0){
                e.cap -= fl;
                g[e.to][e.rev].cap += fl;
                return fl;
            }
        }
        return 0;
    }
    
    T max_flow(int r, int s){
        T res = 0;
        while(true){
            bfs(r);
            if(d[s] == n) return res;
            for(int i = 0; i < n; i++) nx[i] = 0;
            for(T f; (f = dfs(r, s, INF)) > 0;) res += f;
        }
    }
};

struct BipartiteMatching
{
    int n;
    int m;
    Flow<int> g;
    vector<int> match;
    
    BipartiteMatching(int n, int m) : n(n), m(m){
        g.n = n + m + 2;
        g.d.resize(g.n);
        g.nx.resize(g.n);
        g.g.resize(g.n);
        for(int i = 0; i < n; i++) g.add_edge(n + m, i, 1);
        for(int i = n; i < n + m; i++) g.add_edge(i, n + m + 1, 1);
    }
    
    void add_edge(int i, int j, int id = -1){
        g.add_edge(i, j + n, 1, id);
    }
    
    int max_matching(){
        g.max_flow(n + m, n + m + 1);
        for(int i = 0; i < n; i++){
            for(int j = 1; j < (int)g.g[i].size(); j++){
                if(g.g[i][j].cap == 0) match.push_back(g.g[i][j].id);
            }
        }
        return (int)match.size();
    }
};

int main()
{
    int n, m;
    cin >> n >> m;
    string s[103];
    for(int i = 0; i < n; i++) cin >> s[i];
    BipartiteMatching g((n * m) / 2, (n * m + 1) / 2);
    int t = 0;
    P p[20005];
    int c[20005];
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if((i + j) % 2 && s[i][j] == '.'){
                for(int k = 0; k < 4; k++){
                    int u = i + dx[k], v = j + dy[k];
                    if(u >= 0 && u < n && v >= 0 && v < m && s[u][v] == '.'){
                        g.add_edge((i * m + j) / 2, (u * m + v) / 2, t);
                        p[t] = P(i, j);
                        c[t] = k;
                        t++;
                    }
                }
            }
        }
    }
    int ans = g.max_matching();
    cout << ans << endl;
    for(int i : g.match){
        s[p[i].first][p[i].second] = d[c[i]];
        s[p[i].first + dx[c[i]]][p[i].second + dy[c[i]]] = d[(c[i] + 2) % 4];
    }
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++) cout << s[i][j];
        cout << endl;
    }
}


Measured memory_bytes: 5344