#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <vector>
#include <sstream>
#include <string>
#include <functional>
#include <queue>
#include <deque>
#include <stack>
#include <limits>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <fstream>
#include <iterator>
#include <random>
#include <chrono>


#define forr(i,start,count) for (int i = (start); i < (start)+(count); ++i)
#define set_map_includes(set, elt) (set.find((elt)) != set.end())
#define readint(i) int i; cin >> i
#define readll(i) ll i; cin >> i
#define readdouble(i) double i; cin >> i
#define readstring(s) string s; cin >> s

typedef long long ll;

using namespace std;

ll modd = 1000 * 1000 * 1000 + 7;

template<class T>
class NetworkFlow  { 
    public:
    struct Edge {   int v, rev; T flow, C;  }; 
    vector<int> level;
    vector<vector<Edge>> adj;

    NetworkFlow(int V) : level(vector<int>(V)), adj(vector<vector<Edge>>(V))    {   }

    void addEdge(int u, int v, T C)     { 
        Edge a; a.v = v; a.flow = 0; a.C = C; a.rev = adj[v].size();
        Edge b; b.v = u; b.flow = 0; b.C = 0; b.rev = adj[u].size();
        adj[u].push_back(a); adj[v].push_back(b);
    }

    bool BFS(int s, int t)     { 
      for (int i = 0 ; i < level.size(); i++)  {    level[i] = -1;   }
      level[s] = 0;

      queue<int> q; q.push(s);
      while (!q.empty())
      { 
        int u = q.front(); q.pop();
        for (Edge &e : adj[u])        {
            if ((level[e.v] < 0)  && (e.flow < e.C))     {
                level[e.v] = level[u] + 1; q.push(e.v); 
            }
        } 
      } 
      return level[t] < 0 ? false : true ; 
    };

    T sendFlow(int u, T flow, int t, vector<int>& start)    {
      if (u == t) {   return flow;  }
      for (  ; start[u] < adj[u].size(); start[u]++)     { 
        Edge &e = adj[u][start[u]];  
                                      
        if ((level[e.v] == level[u]+1) && (e.flow < e.C))       { 
            T curr_flow = min(flow, e.C - e.flow);
            T temp_flow = sendFlow(e.v, curr_flow, t, start);

            if (temp_flow > 0)      { 
                e.flow += temp_flow;
                adj[e.v][e.rev].flow -= temp_flow; 
                return temp_flow; 
            } 
        } 
      }
      return 0;
    };

   T DinicMaxflow(int s, int t)  { 
      if (s == t) {   return -1; }  
      int total = 0;
  
      while (BFS(s, t) == true)     { 
        vector<int> start(level.size()+1);
        while (T flow = sendFlow(s, numeric_limits<int>::max(), t, start)) {
            total += flow;  }
      }
      return total; 
     }
};

template<class T>
void DinicMaxFlow(int N_vertices, map<pair<int,int>, T>& edges, int s, int t) {
    // call to find max flow in a flow network; edges[pair(i,j)] gives capacity of edge from i to j; N_veritces is number of vertices,
    // s source index, t terminal index
    // function returns max flow in the same map edges

    NetworkFlow<T> g(N_vertices);
    for (auto e : edges) {  g.addEdge(e.first.first, e.first.second, e.second);   }
    g.DinicMaxflow(s, t);
    for (int i = 0; i < g.adj.size(); ++i) {
        for (auto v_to : g.adj[i]) {
            if (edges.find(make_pair(i, v_to.v)) != edges.end()) {
              edges[make_pair(i, v_to.v)] = v_to.flow;
            }
        }
    }
};

void MaxBipartiteMatching(int N_left, int N_right, set<pair<int,int>>& edges) {
    // call to find maximal bipartite matching; edges is a set of edges (vertex numbering beginning with 0 on either side!!!!!!!!!!), 
    // on return only edges in max matcinhg remain
    // N_left is number of vertices on one side (first in pair), N_right is number of vertices on the other side (second in pair)


    map<pair<int,int>,int> e;
    for (auto ed : edges) {  e[make_pair(ed.first, N_left + ed.second)] = 1;   }
    for (int i = 0; i < N_left; ++i) {        e[make_pair(N_left+N_right, i)] = 1;    }
    for (int i = 0; i < N_right; ++i) {        e[make_pair(N_left + i, N_left+N_right+1)] = 1;    }

    DinicMaxFlow<int>(N_left+N_right+2, e, N_left+N_right, N_left+N_right+1);
    for (auto x : e) {
        if ((x.first.first < N_left) && (x.first.second < N_left + N_right) && (x.first.second >= N_left))  {
            if (x.second == 0) {   edges.erase(make_pair(x.first.first, x.first.second - N_left));  }
        }
    }
};


int main()   {

      ios_base::sync_with_stdio(false);

      cout.precision(17);
      mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
      uniform_int_distribution<int> rand_gen(0, modd);   // rand_gen(rng) gets the rand no

//    readint(test_cases);
    int test_cases = 1;
    forr(t, 1, test_cases) {
        readint(n); readint(m);
        vector<string> grid;
        forr(i,0,n) {
            readstring(s); grid.push_back(s);
        }
        vector<pair<int,int>> pts1, pts2;
        map<pair<int,int>,int> dict;
        forr(i,0,n) {
            forr(j,0,m) {
                if (grid[i][j]!='#') {
                    if ((i+j) % 2 == 0) {
                      dict[make_pair(i,j)] = pts1.size();
                      pts1.push_back(make_pair(i,j));
                    } else {
                      dict[make_pair(i,j)] = pts2.size();
                      pts2.push_back(make_pair(i,j));
                    }
                }
            }
        }
        set<pair<int,int>> edges;
        forr(i,0,n) {
            forr(j,0,m) {
                if (grid[i][j]!='#') {
                  if ((i+j) % 2 == 0) {
                    if (set_map_includes(dict, make_pair(i-1,j))) {  edges.insert(make_pair(dict[make_pair(i,j)], dict[make_pair(i-1,j)]));   }
                    if (set_map_includes(dict, make_pair(i+1,j))) {  edges.insert(make_pair(dict[make_pair(i,j)], dict[make_pair(i+1,j)]));   }
                    if (set_map_includes(dict, make_pair(i,j-1))) {  edges.insert(make_pair(dict[make_pair(i,j)], dict[make_pair(i,j-1)]));   }
                    if (set_map_includes(dict, make_pair(i,j+1))) {  edges.insert(make_pair(dict[make_pair(i,j)], dict[make_pair(i,j+1)]));   }
                  }
                }
            }
        }

        MaxBipartiteMatching(pts1.size(), pts2.size(), edges);

        cout << edges.size() << endl;
        for(auto x : edges) {
            pair<int,int> p1 = pts1[x.first], p2 = pts2[x.second];
            if (p1.first==p2.first) {
                grid[p1.first][min(p1.second, p2.second)] = '>';
                grid[p1.first][max(p1.second, p2.second)] = '<';
            } else {
                grid[min(p1.first, p2.first)][p1.second] = 'v';
                grid[max(p1.first, p2.first)][p1.second] = '^';
            }
        }

        forr(i,0,n) {
            cout << grid[i] << endl;
        }

    }
    return 0;
}


Measured memory_bytes: 9040