#include <bits/stdc++.h>
#define FASTIO
//#include <atcoder/maxflow>
//using namespace std;

using ll = long long;
using Vi = std::vector<int>;
using Vl = std::vector<ll>;
using Pii = std::pair<int, int>;
using Pll = std::pair<ll, ll>;

constexpr int I_INF = std::numeric_limits<int>::max();
constexpr ll L_INF = std::numeric_limits<ll>::max();

template <typename T1, typename T2>
inline bool chmin(T1& a, const T2& b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <typename T1, typename T2>
inline bool chmax(T1& a, const T2& b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

class Prints {
private:
    class __Prints {
    public:
        __Prints(const char* sep, const char* term) : sep(sep), term(term) {}
        template <class... Args>
        void operator()(const Args&... args) const { print(args...); }
        template <typename T>
        void pvec(const T& vec, size_t sz) const {
            for (size_t i = 0; i < sz; i++)
                std::cout << vec[i] << (i == sz - 1 ? term : sep);
        }
        template <typename T>
        void pmat(const T& mat, size_t h, size_t w) {
            for (size_t i = 0; i < h; i++)
                for (size_t j = 0; j < w; j++)
                    std::cout << mat[i][j] << (j == w - 1 ? term : sep);
        }

    private:
        const char *sep, *term;
        void print() const { std::cout << term; }
        void print_rest() const { std::cout << term; }
        template <class T, class... Tail>
        void print(const T& head, const Tail&... tail) const { std::cout << head, print_rest(tail...); }
        template <class T, class... Tail>
        void print_rest(const T& head, const Tail&... tail) const { std::cout << sep << head, print_rest(tail...); }
    };

public:
    Prints() {}
    __Prints operator()(const char* sep = " ", const char* term = "\n") const { return __Prints(sep, term); }
};

Prints prints;

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

template <typename Cap>
class MaxFlowGraph {
private:
    struct _Edge {
        int to, rev;
        Cap cap;
        _Edge() noexcept {}
        _Edge(int to, Cap cap, int rev) noexcept : to(to), rev(rev), cap(cap) {}
    };
    std::vector<std::vector<_Edge>> g;
    std::vector<std::pair<int, int>> pos;

public:
    MaxFlowGraph(int n) noexcept : g(n) {}
    int add_edge(int from, int to, Cap cap) noexcept {
        const int m = static_cast<int>(pos.size());
        const int from_id = static_cast<int>(g[from].size());
        int to_id = static_cast<int>(g[to].size());
        pos.emplace_back(from, static_cast<int>(g[from].size()));
        if (from == to) ++to_id;
        g[from].emplace_back(to, cap, to_id);
        g[to].emplace_back(from, 0, from_id);
        return m;
    }
    struct Edge {
        int from, to;
        Cap cap, flow;
        Edge() noexcept {}
        Edge(int from, int to, Cap cap, Cap flow) noexcept
            : from(from), to(to), cap(cap), flow(flow) {}
    };
    Edge get_edge(int i) const noexcept {
        const auto e = g[pos[i].first][pos[i].second];
        const auto re = g[e.to][e.rev];
        return Edge(pos[i].first, e.to, e.cap + re.cap, re.cap);
    }
    std::vector<Edge> edges() const noexcept {
        const int m = static_cast<int>(pos.size());
        std::vector<Edge> res;
        res.reserve(m);
        for (int i = 0; i < m; i++) res.emplace_back(get_edge(i));
        return res;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) noexcept {
        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) noexcept {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) noexcept {
        const int n = static_cast<int>(g.size());
        std::vector<int> level(n), iter(n);
        std::deque<int> que;
        auto bfs = [&](void) noexcept -> void {
            level.assign(n, -1);
            que.clear();
            level[s] = 0;
            que.emplace_back(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop_front();
                int sz = static_cast<int>(g[v].size());
                for (int i = 0; i < sz; i++) {
                    const _Edge& e = g[v][i];
                    if (e.cap > 0 && level[e.to] < 0) {
                        level[e.to] = level[v] + 1;
                        if (e.to == t) return;
                        que.emplace_back(e.to);
                    }
                }
            }
        };
        auto dfs = [&](auto&& self, int v, Cap f) noexcept -> Cap {
            if (v == s) return f;
            const int sz = static_cast<int>(g[v].size());
            const int level_v = level[v];
            Cap res = 0;
            for (int& i = iter[v]; i < sz; i++) {
                _Edge& e = g[v][i];
                _Edge& re = g[e.to][e.rev];
                if (level_v > level[e.to] && re.cap > 0) {
                    int d = self(self, e.to, std::min(f - res, re.cap));
                    if (d > 0) {
                        re.cap -= d;
                        e.cap += d;
                        res += d;
                        if (res == f) break;
                    }
                }
            }
            return res;
        };
        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] < 0) return flow;
            iter.assign(n, 0);
            while (flow < flow_limit) {
                Cap f = dfs(dfs, t, flow_limit - flow);
                if (f == 0) break;
                flow += f;
            }
        }
        return flow;
    }
    std::vector<bool> min_cut(int s) const noexcept {
        const int n = static_cast<int>(g.size());
        std::vector<bool> res(n);
        std::deque<int> que;
        res[s] = true;
        que.emplace_back(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop_front();
            for (const auto& edge : g[v]) {
                if (edge.cap > 0 && !res[edge.to]) {
                    res[edge.to] = true;
                    que.emplace_back(edge.to);
                }
            }
        }
        return res;
    }
};



void solve() {
    int N, M;
    std::cin >> N >> M;
    std::vector<std::string> grid(N);
    for (int i = 0; i < N; i++) {
        std::cin >> grid[i];
    }

    MaxFlowGraph<int> mf_graph(N * M + 2);
    //atcoder::mf_graph<int> mf_graph(N * M + 2);
    int s = N * M, t = N * M + 1;

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (grid[i][j] == '#') continue;
            int v = i * M + j;
            if (~(i + j) & 1) {
                mf_graph.add_edge(s, v, 1);
            }
            else {
                mf_graph.add_edge(v, t, 1);
            }
        }
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if ((i + j) & 1 || grid[i][j] == '#') continue;
            int v0 = i * M + j;
            if (i > 0 && grid[i - 1][j] == '.') {
                int v1 = (i - 1) * M + j;
                mf_graph.add_edge(v0, v1, 1);
            }
            if (i < N - 1 && grid[i + 1][j] == '.') {
                int v1 = (i + 1) * M + j;
                mf_graph.add_edge(v0, v1, 1);
            }
            if (j > 0 && grid[i][j - 1] == '.') {
                int v1 = i * M + j - 1;
                mf_graph.add_edge(v0, v1, 1);
            }
            if (j < M - 1 && grid[i][j + 1] == '.') {
                int v1 = i * M + j + 1;
                mf_graph.add_edge(v0, v1, 1);
            }
        }
    }

    prints()(mf_graph.flow(s, t));

    for (const auto& edge : mf_graph.edges()) {
        if (edge.from == s || edge.to == t || edge.flow == 0) continue;
        int i0 = edge.from / M, j0 = edge.from % M;
        int i1 = edge.to / M, j1 = edge.to % M;
        if (i0 == i1 - 1) {
            grid[i0][j0] = 'v';
            grid[i1][j1] = '^';
        }
        else if (i0 == i1 + 1) {
            grid[i0][j0] = '^';
            grid[i1][j1] = 'v';
        }
        else if (j0 == j1 - 1) {
            grid[i0][j0] = '>';
            grid[i1][j1] = '<';
        }
        else if (j0 == j1 + 1) {
            grid[i0][j0] = '<';
            grid[i1][j1] = '>';
        }
    }

    for (int i = 0; i < N; i++) {
        prints()(grid[i]);
    }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

int main() {
#ifdef FASTIO
    std::cin.tie(nullptr), std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
#endif
#ifdef FILEINPUT
    std::ifstream ifs("./in_out/input.txt");
    std::cin.rdbuf(ifs.rdbuf());
#endif
#ifdef FILEOUTPUT
    std::ofstream ofs("./in_out/output.txt");
    std::cout.rdbuf(ofs.rdbuf());
#endif
    std::cout << std::setprecision(18) << std::fixed;
    solve();
    std::cout << std::flush;
    return 0;
}


Measured memory_bytes: 5336