Problem:
Score : 100 points

Problem Statement

You are given a grid of N rows and M columns. The square at the i-th row and j-th column will be denoted as (i,j).
Some of the squares contain an object. All the remaining squares are empty.
The state of the grid is represented by strings S_1,S_2,\cdots,S_N. The square (i,j) contains an object if S_{i,j}= # and is empty if S_{i,j}= ..

Consider placing 1 \times 2 tiles on the grid. Tiles can be placed vertically or horizontally to cover two adjacent empty squares.
Tiles must not stick out of the grid, and no two different tiles may intersect. Tiles cannot occupy the square with an object.

Calculate the maximum number of tiles that can be placed and any configulation that acheives the maximum.

Constraints

1 \leq N \leq 100

1 \leq M \leq 100

S_i is a string with length M consists of # and ..

Input

Input is given from Standard Input in the following format:

N M
S_1
S_2
\vdots
S_N

Output

On the first line, print the maximum number of tiles that can be placed.

On the next N lines, print a configulation that achieves the maximum.
Precisely, output the strings t_1,t_2,\cdots,t_N constructed by the following way.

t_i is initialized to S_i.

For each (i,j), if there is a tile that occupies (i,j) and (i+1,j), change t_{i,j}:=v, t_{i+1,j}:=^.

For each (i,j), if there is a tile that occupies (i,j) and (i,j+1), change t_{i,j}:=>, t_{i,j+1}:=<.

See samples for further information.

You may print any configulation that maximizes the number of tiles.

Sample Input 1

3 3
#..
..#
...

Sample Output 1

3
#><
vv#
^^.

The following output is also treated as a correct answer.

3
#><
v.#
^><

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Linq;

using E = System.Linq.Enumerable;
using Weight = System.Int32;
using System.Threading;

internal partial class Solver {
    public void Run() {
        var h = ni();
        var w = ni();
        var s = ns(h).Select(x => new StringBuilder(x)).ToArray();
        var dinic = new Dinic(h * w + 2);
        int source = h * w;
        int sink = source + 1;

        int toId(int row, int col) => row * w + col;
        (int Row, int Col) FromId(int id) => (id / w, id % w);
        void AddEdge(int r1, int c1, int r2, int c2) {
            if ((r1 + c1) % 2 == 1) AddEdge(r2, c2, r1, c1);
            else {
                dinic.AddEdge(toId(r1, c1), toId(r2, c2), 1);
            }
        }

        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if ((i + j) % 2 == 0) dinic.AddEdge(source, toId(i, j), 1);
                else dinic.AddEdge(toId(i, j), sink, 1);
            }
        }

        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (s[i][j] == '#') continue;
                if (i + 1 < h && s[i + 1][j] == '.') {
                    AddEdge(i, j, i + 1, j);
                }
                if (j + 1 < w && s[i][j + 1] == '.') {
                    AddEdge(i, j, i, j + 1);
                }
            }
        }
        cout.WriteLine(dinic.Run(source, sink));

        foreach (var edge in dinic.GetEdges()) {
            if (edge.From >= source) continue;
            if (edge.To >= source) continue;
            if (edge.Flow == 0) continue;
            //new { edge.From, edge.To, edge.Flow }.TextDump();
            var (row1, col1) = FromId(edge.From);
            var (row2, col2) = FromId(edge.To);
            if ((row1 + col1) % 2 == 1) continue;
            if ((row2 + col2) % 2 == 0) continue;
            if (row1 == row2) {
                if (col1 < col2) {
                    s[row1][col1] = '>';
                    s[row2][col2] = '<';
                } else {
                    s[row1][col1] = '<';
                    s[row2][col2] = '>';
                }
            } else {
                if (row1 < row2) {
                    s[row1][col1] = 'v';
                    s[row2][col2] = '^';
                } else {
                    s[row1][col1] = '^';
                    s[row2][col2] = 'v';
                }
            }
        }

        for (int i = 0; i < h; i++) {
            cout.WriteLine(s[i]);
        }
    }
}

public class Dinic {
    public readonly int N;
    private readonly List<List<Edge>> adjacents;
    private readonly int[] levels;
    private readonly bool[] used;

    public class Edge {
        public int From, To;
        public Weight Flow, Capacity;
        public Edge Reverse;
        public Edge(int from, int to, Weight capacity, Weight flow = 0) {
            From = from;
            To = to;
            Flow = flow;
            Capacity = capacity;
        }
        public Weight Residue { get { return Capacity - Flow; } }
    }

    public Dinic(int n) {
        N = n;
        adjacents = new List<List<Edge>>();
        levels = new int[N];
        used = new bool[N];
        for (int i = 0; i < N; i++) {
            adjacents.Add(new List<Edge>());
        }
    }

    public void AddEdge(int from, int to, Weight capacity) {
        var e1 = new Edge(from, to, capacity);
        var e2 = new Edge(to, from, 0);
        e1.Reverse = e2;
        e2.Reverse = e1;
        adjacents[from].Add(e1);
        adjacents[to].Add(e2);
    }

    public IEnumerable<Edge> GetEdges() {
        return adjacents.SelectMany(a => a);
    }

    private bool Levelize(int s, int t) {
        for (int i = 0; i < N; i++) {
            levels[i] = -1;
        }
        var queue = new Queue<int>();
        levels[s] = 0;
        queue.Enqueue(s);
        while (queue.Count > 0) {
            int pos = queue.Dequeue();
            foreach (var edge in adjacents[pos]) {
                if (levels[edge.To] == -1 && edge.Residue > 0) {
                    levels[edge.To] = levels[pos] + 1;
                    queue.Enqueue(edge.To);
                }
            }
        }
        return levels[t] != -1;
    }

    private Weight Augment(int pos, int end, Weight cur) {
        int flowOut = 0;
        foreach (var edge in adjacents[pos]) {
            if (levels[edge.To] == levels[pos] + 1) {
                int f = Math.Min(cur - flowOut, edge.Residue);
                if (f <= 0) {
                    continue;
                }

                if ((edge.To == end) || (!used[edge.To] && (f = Augment(edge.To, end, f)) > 0)) {
                    edge.Flow += f;
                    edge.Reverse.Flow -= f;
                    flowOut += f;
                    if (cur - flowOut == 0) {
                        return flowOut;
                    }
                }
            }
        }
        used[pos] = flowOut == 0;
        return flowOut;
    }

    public Weight Run(int source, int sink) {
        int totalFlow = 0;

        while (Levelize(source, sink)) {
            Array.Clear(used, 0, used.Length);
            totalFlow += Augment(source, sink, Weight.MaxValue);
        }

        return totalFlow;
    }
}
// PREWRITEN CODE BEGINS FROM HERE

static public class StringExtensions {
    static public string JoinToString<T>(this IEnumerable<T> source, string separator = " ") {
        return string.Join(separator, source);
    }
}

internal partial class Solver : Scanner {
    static readonly int? StackSizeInMebiByte = null; //50;
    public static void StartAndJoin(Action action, int maxStackSize) {
        var thread = new Thread(new ThreadStart(action), maxStackSize);
        thread.Start();
        thread.Join();
    }

    public static void Main() {
#if LOCAL
        byte[] inputBuffer = new byte[1000000];
        var inputStream = Console.OpenStandardInput(inputBuffer.Length);
        using (var reader = new StreamReader(inputStream, Console.InputEncoding, false, inputBuffer.Length)) {
            Console.SetIn(reader);
            new Solver(Console.In, Console.Out).Run();
        }
#else
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        if (StackSizeInMebiByte.HasValue) {
            StartAndJoin(() => new Solver(Console.In, Console.Out).Run(), StackSizeInMebiByte.Value * 1024 * 1024);
        } else {
            new Solver(Console.In, Console.Out).Run();
        }
        Console.Out.Flush();
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
    private readonly TextWriter cerr;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        cin = reader;
        cout = writer;
        cerr = Console.Error;
    }

    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

#if DEBUG
internal static class LinqPadExtension {
    public static string TextDump<T>(this T obj) {
        if (obj is IEnumerable) return (obj as IEnumerable).Cast<object>().JoinToString().Dump();
        else return obj.ToString().Dump();
    }
    public static T Dump<T>(this T obj) {
        return LINQPad.Extensions.Dump(obj);
    }
}
#endif

public class Scanner {
    private readonly TextReader Reader;
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    private readonly char[] buffer = new char[2 * 1024];
    private int cursor = 0, length = 0;
    private string Token;
    private readonly StringBuilder sb = new StringBuilder(1024);

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        Reader = reader;
    }

    public int NextInt() { return checked((int)NextLong()); }
    public long NextLong() {
        var s = Next();
        long r = 0;
        int i = 0;
        bool negative = false;
        if (s[i] == '-') {
            negative = true;
            i++;
        }
        for (; i < s.Length; i++) {
            r = r * 10 + (s[i] - '0');
#if DEBUG
            if (!char.IsDigit(s[i])) throw new FormatException();
#endif
        }
        return negative ? -r : r;
    }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        string[] array = new string[size];
        for (int i = 0; i < size; i++) {
            array[i] = Next();
        }

        return array;
    }
    public int[] NextIntArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextInt();
        }

        return array;
    }

    public long[] NextLongArray(int size) {
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextLong();
        }

        return array;
    }

    public double[] NextDoubleArray(int size) {
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextDouble();
        }

        return array;
    }

    public string Next() {
        if (Token == null) {
            if (!StockToken()) {
                throw new Exception();
            }
        }
        var token = Token;
        Token = null;
        return token;
    }

    public bool HasNext() {
        if (Token != null) {
            return true;
        }

        return StockToken();
    }

    private bool StockToken() {
        while (true) {
            sb.Clear();
            while (true) {
                if (cursor >= length) {
                    cursor = 0;
                    if ((length = Reader.Read(buffer, 0, buffer.Length)) <= 0) {
                        break;
                    }
                }
                var c = buffer[cursor++];
                if (33 <= c && c <= 126) {
                    sb.Append(c);
                } else {
                    if (sb.Length > 0) break;
                }
            }

            if (sb.Length > 0) {
                Token = sb.ToString();
                return true;
            }

            return false;
        }
    }
}