#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <set>
#include <queue>
#include <stack>
#include <tuple>
#include <cmath>
#include <iomanip>
#include <map>
#include <cstring>
#include <functional>
#include <cctype>
#include <locale>
#define ll long long
#define rep(i,n) for(int i=0;i<(n);i++)
#define rrep(i,n) for(int i=n-1;i>=0;i--)
#define fi first
#define se second
#define pb push_back
#define ALL(a) (a).begin(),(a).end()
using namespace std;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
typedef pair<int,int> P;
typedef pair<long long,long long> Pll;
#define fout(num) cout << fixed << setprecision(20) << (num) << endl
//s[i]=tolower(s[i]); islower(s[i]); cout << tolower(s[i])はバグ
//vector<vector<ll>> dp(n,vector<ll>(n))
//2-dim:vector<vector<Type>> vv(n, vector<Type>(m, d));
//3-dim:vector<vector<vector<Type>>> vvv(n, vector<vector<Type>>(m, vector<Type>(l, d)));

template<typename T>
struct Flow{
private:
    int _n;
    struct _edge {
        int to, rev;
        T cap;
    };
    vector<pair<int, int>> pos;
    vector<vector<_edge>> G;
    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:
    Flow():_n(0){}
    Flow(int n):_n(n),G(n){}
    void add_edge(int from,int to, T cap){
        pos.push_back({from,G[from].size()});
        G[from].push_back({to,(int)G[to].size(),cap});
        G[to].push_back({from,(int)G[from].size()-1,0});
    }
    struct Edge{
        int from,to;
        T cap,flow;
    };
    Edge get_edge(int x){
        auto _e = G[pos[x].first][pos[x].second];
        auto _re = G[_e.to][_e.rev];
        /* from,to,cap */
        return Edge{pos[x].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    T maxflow(int s,int t, T lim){
        vector<int> level(_n),iter(_n);
        /* 流す　*/
        simple_queue que;
        auto bfs=[&](){
            fill(level.begin(),level.end(),-1);
            que.clear();
            level[s]=0; 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, T nf){
            if(v==s) return nf;
            T res=0;
            int lv=level[v];
            for(int& i=iter[v];i<(int)G[v].size();i++){
                _edge& e=G[v][i];
                if(lv<=level[e.to]||G[e.to][e.rev].cap==0)continue;
                T d = self(self,e.to,min(nf-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==nf) break;
            }
            return res;
        };
        T flow=0;
        while(flow<lim){
            bfs();
            if(level[t]==-1) break;
            fill(iter.begin(),iter.end(),0);
            while(flow<lim){
                T f=dfs(dfs,t,lim-flow);
                if(!f) break;
                flow+=f;
            }
        }
        return flow;
    }
    T maxflow(int s,int t){ return maxflow(s,t,numeric_limits<T>::max()); }
};
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
signed main(){
    std::cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);
    int n,m; cin >> n >> m;
    vector<string> s(n);
    rep(i,n) cin >> s[i];
    Flow<int> FG(n*m+2);
    map<P,int> mp;
    int cnt=0;
    rep(i,n){
        rep(j,m){
            if(s[i][j]=='#') continue;
            if((i+j)%2==0) FG.add_edge(n*m,i*m+j,1); // s->x
            else FG.add_edge(i*m+j,n*m+1,1);        // y->g
            cnt++;
            if((i+j)%2==1) continue;
            rep(k,4){
                int ni=i+dx[k],nj=j+dy[k];
                if(0<=ni&&ni<n&&0<=nj&&nj<m&&s[ni][nj]=='.'){
                   FG.add_edge(i*m+j,ni*m+nj,1); // x->y
                    mp[{i*m+j,ni*m+nj}]=cnt;
                    cnt++;
                }
            }
        }
    }
    cout << FG.maxflow(n*m,n*m+1) << endl;
    vector<string> ans=s;
    rep(i,n){
        rep(j,m){
            if(s[i][j]=='#'||(i+j)%2==1) continue;
            rep(k,4){
                int ni=i+dx[k],nj=j+dy[k];
                if(0<=ni&&ni<n&&0<=nj&&nj<m&&s[ni][nj]=='.'){
                    auto x=FG.get_edge(mp[{i*m+j,ni*m+nj}]);
                    int e=x.flow;
                    //cout << i << " " << j <<" "<< ni <<" "<< nj << " " << e << endl;
                    if(e==1){
                        if(k==0){
                            //i+=1
                            ans[i][j]='v';
                            ans[ni][nj]='^';
                        }
                        else if(k==1){
                            //j+=1
                            ans[i][j]='>';
                            ans[ni][nj]='<';
                        }
                        else if(k==2){
                            //i-=1
                            ans[i][j]='^';
                            ans[ni][nj]='v';
                        }else{
                            //j-=1
                            ans[i][j]='<';
                            ans[ni][nj]='>';
                        }
                    }
                }
            }
        }
    }
    rep(i,n){
        rep(j,m){
            cout << ans[i][j];
        }cout << '\n';
    }
}




Measured memory_bytes: 6260