#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <queue>
#include <deque>
#include <algorithm>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <functional>
#include <cassert>
#include <iomanip>
#define vll vector<ll>
#define vvvl vector<vvl>
#define vvl vector<vector<ll>>
#define VV(a, b, c, d) vector<vector<d>>(a, vector<d>(b, c))
#define VVV(a, b, c, d) vector<vvl>(a, vvl(b, vll (c, d)));
#define re(c, b) for(ll c=0;c<b;c++)
#define all(obj) (obj).begin(), (obj).end()
typedef long long int ll;
typedef long double ld;
using namespace std;


template <class T> struct simple_queue {
  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++; }
};

template <class Cap>
struct mf_graph {
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};
  }
  vector<edge> edges() {
    int m = int(pos.size());
    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);
    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;
      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;
  }
  vector<bool> min_cut(int s) {
    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;
  };
  vector<pair<int, int>> pos;
  vector<vector<_edge>> g;
};
int main(){
  ll n, m;scanf("%lld %lld", &n, &m);
  mf_graph<ll> g(20002);//s:30000, t:30001
  vector<string> s(n);
  for(int i=0;i<n;i++) std::cin >> s[i];

  int dx[4] = {0, 0, 1, -1};
  int dy[4] = {1, -1, 0, 0};
  for(int i=0;i<n;i++){
    for(int j=0;j<m;j++){
      if(s[i][j]=='#') continue;
      g.add_edge(20000, i*m+j, 1);
      g.add_edge(i*m+j+10000, 20001, 1);
      for(int k=0;k<4;k++){
        ll x = i + dx[k], y = j + dy[k];
        if(x<0||x>=n||y<0||y>=m||s[x][y]=='#') continue;
        g.add_edge(i*m+j, 10000 + x*m+y, 1);
      }
    }
  }
  ll ans = g.flow(20000, 20001);
  assert(ans%2==0);
  ans /= 2;
  printf("%lld\n", ans);
  vector<mf_graph<ll>::edge> v = g.edges();
  for(auto e:v){
    if(e.flow&&e.from>=0&&e.from<10000&&e.to<20000&&e.to>=10000){
      ll ax = e.from / m, ay = e.from % m;
      ll bx = (e.to -10000) / m, by = (e.to - 10000) % m;
      //std::cout << ax << " " << ay << " " << bx << " " << by << '\n';
      if(s[ax][ay]=='.'&&s[bx][by]=='.'){
        if(ax==bx){
          if(ay > by) swap(ay, by);
          s[ax][ay] = '>', s[bx][by] = '<';
        }
        if(ay==by){
          if(ax > bx) swap(ax, bx);
          s[ax][ay] = 'v', s[bx][by] = '^';
        }
      }
    }
  }
  for(int i=0;i<n;i++) std::cout << s[i] << '\n';
}


Measured memory_bytes: 9472