#pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
// #include<ext/pb_ds/assoc_container.hpp>
// #include<ext/pb_ds/tree_policy.hpp>
// #include<ext/pb_ds/tag_and_trait.hpp>
// using namespace __gnu_pbds;
// #include<boost/multiprecision/cpp_int.hpp>
// namespace multiprecisioninteger = boost::multiprecision;
// using cint=multiprecisioninteger::cpp_int;
using namespace std;
using ll=long long;
#define double long double
using datas=pair<ll,ll>;
using ddatas=pair<double,double>;
using tdata=pair<ll,datas>;
using vec=vector<ll>;
using mat=vector<vec>;
using pvec=vector<datas>;
using pmat=vector<pvec>;
// using llset=tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;
#define For(i,a,b) for(i=a;i<(ll)b;++i)
#define bFor(i,b,a) for(i=b,--i;i>=(ll)a;--i)
#define rep(i,N) For(i,0,N)
#define rep1(i,N) For(i,1,N)
#define brep(i,N) bFor(i,N,0)
#define brep1(i,N) bFor(i,N,1)
#define all(v) (v).begin(),(v).end()
#define allr(v) (v).rbegin(),(v).rend()
#define vsort(v) sort(all(v))
#define vrsort(v) sort(allr(v))
#define endl "\n"
#define eb emplace_back
#define print(v) cout<<v<<endl
#define printyes cout<<"Yes"<<endl
#define printno cout<<"No"<<endl
#define printYES cout<<"YES"<<endl
#define printNO cout<<"NO"<<endl
#define output(v) do{bool f=0;for(auto outi:v){cout<<(f?" ":"")<<outi;f=1;}cout<<endl;}while(0)
#define matoutput(v) do{for(auto outimat:v)output(outimat);}while(0)
const ll mod=1000000007;
// const ll mod=998244353;
const ll inf=1LL<<60;
const double PI = acos(-1);
const double eps = 1e-9;
template<class T> inline bool chmax(T& a,T b){bool x=a<b;if(x)a=b;return x;} 
template<class T> inline bool chmin(T& a,T b){bool x=a>b;if(x)a=b;return x;} 

void startupcpp(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout<<fixed<<setprecision(15);
}
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())});
    int from_id=int(g[from].size());
    int to_id=int(g[to].size())+int(from==to);
    g[from].push_back(_edge{to,to_id,cap});
    g[to].push_back(_edge{from,from_id,0});
    return m;
  }

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

  edge get_edge(int i){
    assert(0<=i&&i<int(pos.size()));
    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(){
    vector<edge> result;
    for(int i=0;i<int(pos.size());i++){
      result.push_back(get_edge(i));
    }
    return result;
  }
  void change_edge(int i,Cap new_cap,Cap new_flow){
    assert(0<=i&&i<int(pos.size()));
    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,numeric_limits<Cap>::max());
  }
  Cap flow(int s,int t,Cap flow_limit){
    assert(0<=s&&s<_n);
    assert(0<=t&&t<_n);
    assert(s!=t);

    vector<int> level(_n),iter(_n);
    simple_queue<int> que;

    auto bfs=[&](){
      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,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;
  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;}
  };
};
int main(){
  // startupcpp();
  int i,j,H,W;
  cin>>H>>W;
  vector<string> g(H);
  mf_graph<int> flaw(H*W+2);
  rep(i,H){
    cin>>g[i];
    rep(j,W){
      if((i+j)&1)flaw.add_edge(i*W+j,H*W+1,1);
      else flaw.add_edge(H*W,i*W+j,1);
      if(g[i][j]=='#')continue;
      if(i&&g[i][j]==g[i-1][j]){
        if((i+j)&1)flaw.add_edge((i-1)*W+j,i*W+j,1);
        else flaw.add_edge(i*W+j,(i-1)*W+j,1);
      }
      if(j&&g[i][j]==g[i][j-1]){
        if((i+j)&1)flaw.add_edge(i*W+j-1,i*W+j,1);
        else flaw.add_edge(i*W+j,i*W+j-1,1);
      }
    }
  }
  print(flaw.flow(H*W,H*W+1));
  auto v=flaw.edges();
  for(auto x:v){
    if(!x.flow||max(x.from,x.to)>=H*W)continue;
    if(x.from>x.to)swap(x.from,x.to);
    i=x.from/W;j=x.from%W;
    if(i>=H)continue;
    if(x.to-x.from==W){
      g[i][j]='v';
      g[i+1][j]='^';
    }else{
      g[i][j]='>';
      g[i][j+1]='<';
    }
  }
  rep(i,H)print(g[i]);
}

Measured memory_bytes: 5664