#include<atcoder/all>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<iomanip>
#include<cmath>

#define REP(i,n) for (int i = 0; (i) < (n); ++ (i))
#define FOR(i,n) for (int i = 1; (i) <= (n); ++ (i))
#define dump(x)  cout << #x << " = " << (x) << endl;
#define pb push_back
#define int long long

const int INF = 1e18;
const int MOD = 1e9+7;
//const lint LINF = 1e18;
const double eps = 0.000000001;//もとの値の10^(-16)まで

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

using namespace std;
using namespace atcoder;



//typedef pair<int, int> P;
//priority_queue< P, vector<P>, greater<P> > q;//ダイクストラの時、greaterで小さい順
//cout << fixed << setprecision(10) << ans << endl;
//int gcd(int a,int b){return b?gcd(b,a%b):a;}


// mf_graph<Cap> graph(int n) // n頂点0辺のグラフを作る、Capは容量の型
// add_edge(int from, int to, Cap cap); // fromからtoへ最大容量cap、流量 0 の辺を追加, (何番目に追加された辺かを返す)
// Cap graph.flow(int s, int t); //頂点 ss から tt へ流せる限り流し、流せた量を返す。
// Cap graph.flow(int s, int t, Cap flow_limit); 頂点 ss から tt へ流量 flow_limitに達するまで流せる限り流し、流せた量を返す。O(n^2m)
// vector<bool> graph.min_cut(int s)
/* struct mf_graph<Cap>::edge {
    int from, to;
    Cap cap, flow;
};

(1) mf_graph<Cap>::edge graph.get_edge(int i);
(2) vector<mf_graph<Cap>::edge> graph.edges();
*/


int ban[200][200];
char ban2[200][200];

signed main(){
    int n,m;
    cin >> n >> m;
    REP(i,n){
        string s1;
        cin >> s1;
        REP(j,m){
            if(s1[j]=='#'){
                ban[i][j] = 1;
                ban2[i][j] = '#';
            }
            else{
                ban[i][j] = 2;
                ban2[i][j] = '.';
            }
        }
    }
    mf_graph<int> graph(n*m+2);

    int s = n*m;
    int t = n*m+1;
    REP(i,n){
        REP(j,m){
            if(ban[i][j]==2){
                if((i+j)%2==0) graph.add_edge(s,i*m+j,1);
                else graph.add_edge(i*m+j,t,1);
            }
        }
    }
    REP(i,n){
        REP(j,m){
            if(ban[i][j]==1) continue;
            REP(hou,4){
                int ni = i + dx[hou];
                int nj = j + dy[hou];
                if(ni<0 || ni>=n || nj<0 || nj>=m) continue;
                if(ban[ni][nj]==1) continue;
                if((i+j)%2==0) graph.add_edge(i*m+j,ni*m+nj,1);
            } 

        }
    }
    cout << graph.flow(s,t) << endl;
    //REP(i,n*m+2){
        //cout << graph.min_cut(s)[i] << endl;
    //}

    vector< mf_graph<int>::edge > edges = graph.edges();
    
    REP(i,edges.size()){
        mf_graph<int>::edge nowedge = edges[i];
        if(nowedge.from==s||nowedge.to==t||nowedge.flow==0) continue;
        //dump(nowedge.from);
        //dump(nowedge.to);
        int i1 = nowedge.from / m;
        int j1 = nowedge.from % m;
        int i2 = nowedge.to / m;
        int j2 = nowedge.to % m;
        //dump(i1);
        //dump(i2);
        //dump(j1);
        //dump(j2);
        if(i1-i2==-1){
            ban2[i1][j1] = 'v';
            ban2[i2][j2] = '^';
        }
        else if(i2-i1==-1){
            ban2[i1][j1] = '^';
            ban2[i2][j2] = 'v';
        }
        else if(j1-j2==-1){
            ban2[i1][j1] = '>';
            ban2[i2][j2] = '<';
        }
        else if(j2-j1==-1){
            ban2[i1][j1] = '<';
            ban2[i2][j2] = '>';
        }
    }
    REP(i,n){
        REP(j,m){
            cout << ban2[i][j];
        }
        cout << endl;
    }
    return 0;
}

Measured memory_bytes: 6468