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.#
^><



Sample input:
3 3
#..
..#
...


Sample output:
3
#><
vv#
^^.

Submission status: Runtime Error

Solution code:
#test
NUMERIC_LIMITS = 10 ** 18
import queue
class maxFlow:
  class edge:
    def __init__(s, frm, to, cap, flow):
      s.frm, s.to = frm, to
      s.cap, s.flow = cap, flow

  def __init__(s, n):
    s._n = n
    s.g = [[] for _ in range(n)]
    s.pos = []

  def add_edge(s, frm, to, cap):
    m = len(s.pos)
    s.pos.append([frm, len(s.g[frm])])
    s.g[frm].append(s._edge(to, len(s.g[to]), cap))
    s.g[to].append(s._edge(frm,len(s.g[frm]) - 1, 0))
    return m

  def get_edge(s, i):
    m = len(s.pos)
    _e = s.g[s.pos[i][0]][s.pos[i][1]]
    _re = s.g[_e.to][_e.rev]
    return s.edge(s.pos[i][0], _e.to, _e.cap + _re.cap, _re.cap)

  def edges(s):
    m = len(s.pos)
    result = []
    for i in range(m):
      result.append(s.get_edge(i))
    return result

  def change_edge(s, i, new_cap, new_flow):
    m = len(s.pos)
    _e = s.g[s.pos[i].to][s.pos[i].rev]
    _re = s.g[_e.to][_e.rev]
    _e.cap = new_cap - new_flow
    _re.cap = new_flow

  def flow(self, s, t, flow_limit = NUMERIC_LIMITS):
    level = [0] * self._n
    iter = [0] * self._n 

    def bfs():
      for i in range(self._n):
        level[i] = -1
      level[s] = 0
      que = queue.Queue()
      que.put(s)
      while not que.empty():
        v = que.get()
        for e in self.g[v]:
           if e.cap == 0 or level[e.to] >= 0: continue
           level[e.to] = level[v] + 1
           if e.to == t: return
           que.put(e.to)
    def dfs(this, v, up):
      if v == s: return up
      res = 0
      level_v = level[v]
      for i in range(iter[v], len(self.g[v])):
        e = self.g[v][i]
        if level_v <= level[e.to] or self.g[e.to][e.rev].cap == 0: continue
        d = this(this, e.to, min(up - res, self.g[e.to][e.rev].cap))
        if d <= 0: continue
        self.g[v][i].cap += d
        self.g[e.to][e.rev].cap -= d
        res += d
        if res == up: break
      return res

    flow = 0
    while flow < flow_limit:
      bfs()
      if level[t] == -1: break
      for i in range(self._n): iter[i]
      while flow < flow_limit:
        f = dfs(dfs, t, flow_limit - flow)
        if not f: break
        flow += f
    return flow

  def min_cut(self, s):
    visited = [False] * self._n
    que = queue.Queue()
    que.put(s)
    while not que.empty():
      p = que.get()
      visited[p] = True
      for e in self.g[p]:
        if e.cap and not visited[e.to]:
          visited[e.to] = True
          que.put(e.to)
    return visited

  class _edge:
    def __init__(s, to, rev, cap):
      s.to, s.rev = to, rev
      s.cap = cap




N, M = list(map(int, input().split()))
S = [list(input()) for _ in range(N)]

stop = "#"

flow = maxFlow(N * M + 2)
s = N * M
t = N * M + 1
for x in range(N):
  for y in range(M):
    if S[x][y] == stop: continue
    p = (x + y) % 2
    n = x * M + y
    if p:
      flow.add_edge(s, n, 1)
      for h, w in [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]]:
        if h < 0: continue
        if h >= N: continue
        if w < 0: continue
        if w >= M: continue
        if S[h][w] == stop: continue
        m = h * M + w
        flow.add_edge(n, m, 1)
    else:
      flow.add_edge(n, t, 1)

ans = flow.flow(s, t)

edges = flow.edges()
for edge in edges:
  if edge.flow == 0: continue
  if edge.frm == s: continue
  if edge.to == t: continue
  frm, to = edge.frm, edge.to
  fy, ty = frm % M, to % M
  fx, tx = (frm - fy) // N, (to - ty) // N
  
  if fx == tx:
    if fy > ty:
      fy, ty = ty, fy
    S[fx][fy] = ">"
    S[tx][ty] = "<"
  else:
    if fx > tx:
      fx, tx = tx, fx
    S[fx][fy] = "v"
    S[tx][ty] = "^"

print(ans)
for s in S:
  print("".join(s))

Submission status: Runtime Error

Solution code:
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_flow, maximum_bipartite_matching
import copy
N, M = [int(_) for _ in input().split()]
A = [['#'] * (M + 2)] + [list('#' + input() + '#')
                         for _ in range(N)] + [['#'] * (M + 2)]
A2 = copy.deepcopy(A)
S = ''.join(''.join(a) for a in A)

X = []
Y = []
for i in range((N + 2) * (M + 2)):
    if S[i] == '#':
        continue
    x, y = divmod(i, M + 2)
    if x in [0, N + 1]:
        continue
    if y in [0, M + 1]:
        continue
    for dx, dy in ((1, 0), (0, 1), (-1, 0), (0, -1)):
        nx, ny = x + dx, y + dy
        i2 = nx * (M + 2) + ny
        if S[i2] == '#':
            continue
        X += [i]
        Y += [i2]
perm = maximum_bipartite_matching(csr_matrix(([1] * len(X), (X, Y))))
print((perm != -1).sum() // 2)
for i, j in enumerate(perm):
    if j == -1:
        continue
    if i > j:
        i, j = j, i
    x1, y1 = divmod(i, M + 2)
    x2, y2 = divmod(j, M + 2)
    if j == i + 1:
        A2[x1][y1] = '>'
        A2[x2][y2] = '<'
    else:
        A2[x1][y1] = 'v'
        A2[x2][y2] = '^'
ans = []
for ss in A2[1:-1]:
    ans += [''.join(ss[1:-1])]
print('\n'.join(ans))

Submission status: Runtime Error

Solution code:
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_flow, maximum_bipartite_matching
import copy
N, M = [int(_) for _ in input().split()]
A = [['#'] * (M + 2)] + [list('#' + input() + '#')
                         for _ in range(N)] + [['#'] * (M + 2)]
A2 = copy.deepcopy(A)
S = ''.join(''.join(a) for a in A)

X = []
Y = []
for i in range((N + 2) * (M + 2)):
    if S[i] == '#':
        continue
    x, y = divmod(i, M + 2)
    if (x - y) % 2:
        continue
    if x in [0, N + 1]:
        continue
    if y in [0, M + 1]:
        continue
    for dx, dy in ((1, 0), (0, 1), (-1, 0), (0, -1)):
        nx, ny = x + dx, y + dy
        i2 = nx * (M + 2) + ny
        if S[i2] == '#':
            continue
        X += [i]
        Y += [i2]
perm = maximum_bipartite_matching(csr_matrix(([1] * len(X), (X, Y))))
print((perm != -1).sum())
for i, j in enumerate(perm):
    if j == -1:
        continue
    if i > j:
        i, j = j, i
    x1, y1 = divmod(i, M + 2)
    x2, y2 = divmod(j, M + 2)
    if j == i + 1:
        A2[x1][y1] = '>'
        A2[x2][y2] = '<'
    else:
        A2[x1][y1] = 'v'
        A2[x2][y2] = '^'
ans = []
for ss in A2[1:-1]:
    ans += [''.join(ss[1:-1])]
print('\n'.join(ans))

Submission status: Runtime Error

Solution code:
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_flow, maximum_bipartite_matching
import copy
N, M = [int(_) for _ in input().split()]
A = [['#'] * (M + 2)] + [list('#' + input() + '#')
                         for _ in range(N)] + [['#'] * (M + 2)]
A2 = copy.deepcopy(A)
S = ''.join(''.join(a) for a in A)

X = []
Y = []
for i in range((N + 2) * (M + 2)):
    if S[i] == '#':
        continue
    x, y = divmod(i, M + 2)
    if (x - y) % 2:
        continue
    if x in [0, N + 1]:
        continue
    if y in [0, M + 1]:
        continue
    for dx, dy in ((1, 0), (0, 1), (-1, 0), (0, -1)):
        nx, ny = x + dx, y + dy
        i2 = nx * (M + 2) + ny
        if S[i2] == '#':
            continue
        X += [i]
        Y += [i2]
perm = maximum_bipartite_matching(csr_matrix(([1] * len(X), (X, Y))))
for i, j in enumerate(perm):
    if j == -1:
        continue
    if i > j:
        i, j = j, i
    x1, y1 = divmod(i, M + 2)
    x2, y2 = divmod(j, M + 2)
    if j == i + 1:
        A2[x1][y1] = '>'
        A2[x2][y2] = '<'
    else:
        A2[x1][y1] = 'v'
        A2[x2][y2] = '^'
ans = []
for ss in A2[1:-1]:
    ans += [''.join(ss[1:-1])]
print('\n'.join(ans))

Submission status: Runtime Error

Solution code:
class BipartiteMatching:
    def __init__(self, N, M):
        self.N = N
        self.M = M
        self.pairA = [-1] * N
        self.pairB = [-1] * M
        self.edge = [[] for _ in range(N)]
        self.was = [0] * N
        self.iter = 0

    def add(self, s, t):
        self.edge[s].append(t)

    def _DFS(self, s):
        self.was[s] = self.iter
        for t in self.edge[s]:
            if self.pairB[t] == -1:
                self.pairA[s] = t
                self.pairB[t] = s
                return True
        for t in self.edge[s]:
            if self.was[self.pairB[t]] != self.iter and self._DFS(self.pairB[t]):
                self.pairA[s] = t
                self.pairB[t] = s
                return True
        return False

    def solve(self):
        res = 0
        while True:
            self.iter += 1
            found = 0
            for i in range(self.N):
                if self.pairA[i] == -1 and self._DFS(i):
                    found += 1
            if not found:
                break
            res += found
        return res


DX = (-1, 0, 1, 0, -1, -1, 1, 1)
DY = (0, 1, 0, -1, -1, 1, -1, 1)
DX = DX[:4]
DY = DY[:4]


H, W = map(int, input().split())
grid = [list(input()) for _ in range(H)]
U = H * W


def num(x, y):
    return W * x + y


def coo(n):
    return divmod(n, W)


match = BipartiteMatching(U, U)
for i, si in enumerate(grid):
    for j, s in enumerate(si):
        if s == "#":
            continue
        if (i + j) % 2 == 1:
            continue

        x = num(i, j)
        for dx, dy in zip(DX, DY):
            nx = i + dx
            ny = j + dy
            if nx < 0 or nx >= H or ny < 0 or ny >= W:
                continue
            if grid[nx][ny] == ".":
                y = num(nx, ny)
                match.add(x, y)

ans = match.solve()
for i, j in enumerate(match.pairA):
    if j == -1:
        continue
    if i > j:
        i, j = j, i
    if i + 1 == j:
        x, y = coo(i)
        grid[x][y] = ">"
        x, y = coo(j)
        grid[x][y] = "<"
    else:
        x, y = coo(i)
        grid[x][y] = "v"
        x, y = coo(j)
        grid[x][y] = "^"

print(ans)
for g in grid:
    print("".join(g))

Submission status: Runtime Error

Solution code:
# https://atcoder.jp/contests/practice2/submissions/16598132
# 上記のリンクの提出をいじらせてもらってます。

from collections import deque


class mf_graph:

    __slots__ = ["N", "graph"]

    def __init__(self, N):
        self.N = N
        self.graph = [[] for _ in range(N)]

    def add_edge(self, v, w, cap):
        edge = [w, cap, None]
        edge[2] = rev_edge = [v, 0, edge]
        self.graph[v].append(edge)
        self.graph[w].append(rev_edge)

    def bfs(self, s, t):
        self.level = [None]*self.N
        q = deque([s])
        self.level[s] = 0
        while q:
            v = q.popleft()
            lw = self.level[v]+1
            for w, cap, _ in self.graph[v]:
                if cap and self.level[w] is None:
                    self.level[w] = lw
                    q.append(w)
        return self.level[t] is not None

    def dfs(self, s, t, up):
        st = deque([t])
        while st:
            v = st[-1]
            if v == s:
                st.pop()
                flow = up
                for w in st:
                    e = self.graph[w][self.it[w]][2]
                    flow = min(flow, e[1])
                for w in st:
                    e = self.graph[w][self.it[w]]
                    e[1] += flow
                    e[2][1] -= flow
                return flow
            lv = self.level[v]
            while self.it[v] < len(self.graph[v]):
                w, _, e = self.graph[v][self.it[v]]
                cap = e[1]
                if cap and self.level[w] is not None:
                    if lv > self.level[w]:
                        st.append(w)
                        break
                self.it[v] += 1
            if self.it[v] == len(self.graph[v]):
                st.pop()
                self.level[v] = self.N
        return 0

    def flow(self, s, t, flow_limit=float('inf')):
        flow = 0
        while flow < flow_limit and self.bfs(s, t):
            self.it = [0]*self.N
            while flow < flow_limit:
                f = self.dfs(s, t, flow_limit-flow)
                if not f:
                    break
                flow += f
        return flow

    def min_cut(self, s):
        visited = [False]*self.N
        q = deque([s])
        while q:
            v = q.pop()
            visited[v] = True
            for w, cap, _ in self.graph[v]:
                if cap and not visited[w]:
                    q.append(w)


N, M = map(int, input().split())
S = [list(input()) for i in range(N)]
dc = mf_graph(N*M+2)

s = N*M
t = N*M+1
for i in range(N):
    for j in range(M):
        if (i+j) % 2 == 0:
            dc.add_edge(s, M*i+j, 1)
        else:
            dc.add_edge(M*i+j, t, 1)

for i in range(N):
    for j in range(M):
        if j+1 < M and S[i][j] == "." and S[i][j+1] == ".":
            u, v = M*i+j, M*i+j+1
            if (i+j) % 2 == 1:
                u, v = v, u
            dc.add_edge(u, v, 1)
        if i+1 < N and S[i][j] == "." and S[i + 1][j] == ".":
            u, v = M*i+j, M*(i+1)+j
            if (i+j) % 2 == 1:
                u, v = v, u
            dc.add_edge(u, v, 1)

print(dc.flow(s, t))
for u in range(N*M+2):
    for v, cap, _ in dc.graph[u]:
        ui, uj = divmod(u, M)
        vi, vj = divmod(v, M)
        if (ui+uj) % 2 == 0 and cap == 0 and u != s and u != t and v != s and v != t:
            if ui+1 == vi:
                S[ui][uj] = "v"
                S[vi][vj] = "^"
            elif ui == vi+1:
                S[ui][uj] = "^"
                S[vi][vj] = "v"
            elif uj+1 == vj:
                S[ui][uj] = ">"
                S[vi][vj] = "<"
            elif uj == vj+1:
                S[ui][uj] = "<"
                S[vi][vj] = ">"

for res in S:
    print("".join(res))

Submission status: Runtime Error

Solution code:
# Dinic's algorithm
#https://tjkendev.github.io/procon-library/python/max_flow/dinic.htmlより
from collections import deque
class Dinic:
    def __init__(self, N):
        self.N = N
        self.G = [[] for i in range(N)]

    def add_edge(self, fr, to, cap):
        forward = [to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)

    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)

    def bfs(self, s, t):
        self.level = level = [None]*self.N
        deq = deque([s])
        level[s] = 0
        G = self.G
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        return level[t] is not None

    def dfs(self, v, t, f):
        if v == t:
            return f
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0

    def flow(self, s, t):
        flow = 0
        INF = 10**9 + 7
        G = self.G
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow

N,M = map(int, input().split())
S = [list(input()) for i in range(N)]
dc = Dinic(N*M+2)
 
s =N*M
t = N*M+1
for i in range(N):
    for j in range(M):
        if (i+j) % 2 == 0:
            dc.add_edge(s,M*i+j,1)
        else:
            dc.add_edge(M*i+j,t,1)
 
for i in range(N):
    for j in range(M):
        if j+1 < M and S[i][j] == "." and S[i][j+1] == ".":
            u,v = M*i+j,M*i+j+1
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u, v, 1)
        if i+1 < N and S[i][j] == "." and S[i + 1][j] == ".":
            u,v = M*i+j, M*(i+1)+j
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u,v,1)
 
print(dc.flow(s, t))
for u in range(N*M+2):
    for v, cap, _ in dc.graph[u]:
        ui, uj = divmod(u, M)
        vi, vj = divmod(v, M)
        if (ui+uj) % 2 == 0 and cap == 0 and u != s and u != t and v != s and v!= t:
            if ui+1 == vi:
                S[ui][uj] = "v"
                S[vi][vj] = "^"
            elif ui == vi+1:
                S[ui][uj] = "^"
                S[vi][vj] = "v"
            elif uj+1 == vj:
                S[ui][uj] = ">"
                S[vi][vj] = "<"
            elif uj == vj+1:
                S[ui][uj] = "<"
                S[vi][vj] = ">"
 
for res in S:
    print("".join(res))

Submission status: Runtime Error

Solution code:
# Dinic's algorithm
#https://tjkendev.github.io/procon-library/python/max_flow/dinic.htmlより
from collections import deque
class Dinic:
    def __init__(self, N):
        self.N = N
        self.G = [[] for i in range(N)]

    def add_edge(self, fr, to, cap):
        forward = [to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)

    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)

    def bfs(self, s, t):
        self.level = level = [None]*self.N
        deq = deque([s])
        level[s] = 0
        G = self.G
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        return level[t] is not None

    def dfs(self, v, t, f):
        if v == t:
            return f
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0

    def flow(self, s, t):
        flow = 0
        INF = 10**9 + 7
        G = self.G
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow

N,M = map(int, input().split())
S = [list(input()) for i in range(N)]
dc = mf_graph(N*M+2)
 
s =N*M
t = N*M+1
for i in range(N):
    for j in range(M):
        if (i+j) % 2 == 0:
            dc.add_edge(s,M*i+j,1)
        else:
            dc.add_edge(M*i+j,t,1)
 
for i in range(N):
    for j in range(M):
        if j+1 < M and S[i][j] == "." and S[i][j+1] == ".":
            u,v = M*i+j,M*i+j+1
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u, v, 1)
        if i+1 < N and S[i][j] == "." and S[i + 1][j] == ".":
            u,v = M*i+j, M*(i+1)+j
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u,v,1)
 
print(dc.flow(s, t))
for u in range(N*M+2):
    for v, cap, _ in dc.graph[u]:
        ui, uj = divmod(u, M)
        vi, vj = divmod(v, M)
        if (ui+uj) % 2 == 0 and cap == 0 and u != s and u != t and v != s and v!= t:
            if ui+1 == vi:
                S[ui][uj] = "v"
                S[vi][vj] = "^"
            elif ui == vi+1:
                S[ui][uj] = "^"
                S[vi][vj] = "v"
            elif uj+1 == vj:
                S[ui][uj] = ">"
                S[vi][vj] = "<"
            elif uj == vj+1:
                S[ui][uj] = "<"
                S[vi][vj] = ">"
 
for res in S:
    print("".join(res))

Submission status: Runtime Error

Solution code:
from collections import deque

class mf_graph:
    def __init__(self,N):
        self.N = N
        self.graph = [[] for _ in range(N)]
    
    def add_edge(self,v,w,cap):
        edge = (w,cap,None)
        edge[2] = rev_edge = (v,0,edge)
        self.graph[v].append(edge)
        self.graph[w].append(rev_edge)
    
    def bfs(self,s,t):
        self.level = [None]*self.N
        q = deque([s])
        self.level[s] = 0
        while q:
            v = q.popleft()
            lw = self.level[v]+1
            for w,cap,_ in self.graph[v]:
                if cap and self.level[w] is None:
                    self.level[w] = lw
                    q.append(w)
        return self.level[t] is not None
    
    def dfs(self,s,t,up):
        st = deque([t])
        while st:
            v = st[-1]
            if v == s:
                st.pop()
                flow = up
                for w in st:
                    e = self.graph[w][self.it[w]][2]
                    flow = min(flow,e[1])
                for w in st:
                    e = self.graph[w][self.it[w]]
                    e[1] += flow
                    e[2][1] -= flow
                return flow
            lv = self.level[v]
            while self.it[v] < len(self.graph[v]):
                w,_,e = self.graph[v][self.it[v]]
                cap = e[1]
                if cap and self.level[w] is not None:
                    if lv > self.level[w]:
                        st.append(w)
                        break
                self.it[v] += 1
            if self.it[v] == len(self.graph[v]):
                st.pop()
                self.level[v] = self.N
        return 0
    
    def flow(self,s,t,flow_limit=float('inf')):
        flow = 0
        while flow < flow_limit and self.bfs(s,t):
            self.it = [0]*self.N
            while flow < flow_limit:
                f = self.dfs(s,t,flow_limit-flow)
                if not f:
                    break
                flow += f
        return flow

    def min_cut(self,s):
        visited = [False]*self.N
        q = deque([s])
        while q:
            v = q.pop()
            visited[v] = True
            for w,cap,_ in self.graph[v]:
                if cap and not visited[w]:
                    q.append(w)

N,M = map(int, input().split())
S = [list(input()) for i in range(N)]
dc = mf_graph(N*M+2)

s =N*M
t = N*M+1
for i in range(N):
    for j in range(M):
        if (i+j) % 2 == 0:
            dc.add_edge(s,M*i+j,1)
        else:
            dc.add_edge(M*i+j,t,1)

for i in range(N):
    for j in range(M):
        if j+1 < M and S[i][j] == "." and S[i][j+1] == ".":
            u,v = M*i+j,M*i+j+1
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u, v, 1)
        if i+1 < N and S[i][j] == "." and S[i + 1][j] == ".":
            u,v = M*i+j, M*(i+1)+j
            if (i+j) % 2 == 1:
                u,v = v,u
            dc.add_edge(u,v,1)

print(dc.flow(s, t))
for u in range(N*M+2):
    for v, cap, _ in dc.graph[u]:
        ui, uj = divmod(u, M)
        vi, vj = divmod(v, M)
        if (ui+uj) % 2 == 0 and cap == 0 and u != s and u != t and v != s and v!= t:
            if ui+1 == vi:
                S[ui][uj] = "v"
                S[vi][vj] = "^"
            elif ui == vi+1:
                S[ui][uj] = "^"
                S[vi][vj] = "v"
            elif uj+1 == vj:
                S[ui][uj] = ">"
                S[vi][vj] = "<"
            elif uj == vj+1:
                S[ui][uj] = "<"
                S[vi][vj] = ">"

for res in S:
    print("".join(res))

Submission status: Runtime Error

Solution code:
class Weigthed_Digraph:
    #入力定義
    def __init__(self,vertex=[]):
        self.vertex=set(vertex)

        self.edge_number=0
        self.vertex_number=len(vertex)

        self.adjacent_out={v:{} for v in vertex} #出近傍(vが始点)
        self.adjacent_in={v:{} for v in vertex} #入近傍(vが終点)

    #頂点の追加
    def add_vertex(self,*adder):
        for v in adder:
            if v not in self.vertex:
                self.adjacent_in[v]={}
                self.adjacent_out[v]={}

                self.vertex_number+=1
                self.vertex.add(v)

    #辺の追加(更新)
    def add_edge(self,From,To,weight=1):
        for v in [From,To]:
            if v not in self.vertex:
                self.add_vertex(v)

        if To not in self.adjacent_in[From]:
            self.edge_number+=1

        self.adjacent_out[From][To]=weight
        self.adjacent_in[To][From]=weight

    #辺を除く
    def remove_edge(self,From,To):
        for v in [From,To]:
            if v not in self.vertex:
                self.add_vertex(v)

        if To in self.adjacent_out[From]:
            del self.adjacent_out[From][To]
            del self.adjacent_in[To][From]
            self.edge_number-=1

    #頂点を除く
    def remove_vertex(self,*vertexes):
        for  v in vertexes:
            if v in self.vertex:
                self.vertex_number-=1

                for u in self.adjacent_out[v]:
                    del self.adjacent_in[u][v]
                    self.edge_number-=1
                del self.adjacent_out[v]

                for u in self.adjacent_in[v]:
                    del self.adjacent_out[u][v]
                    self.edge_number-=1
                del self.adjacent_in[v]

    #Walkの追加
    def add_walk(self,*walk):
        pass

    #Cycleの追加
    def add_cycle(self,*cycle):
        pass

    #頂点の交換
    def __vertex_swap(self,p,q):
        self.vertex.sort()

    #グラフに頂点が存在するか否か
    def vertex_exist(self,v):
        return v in self.vertex

    #グラフに辺が存在するか否か
    def edge_exist(self,From,To):
        if not(self.vertex_exist(From) and self.vertex_exist(To)):
            return False
        return To in self.adjacent_out[From]

    #近傍
    def neighbohood(self,v):
        if not self.vertex_exist(v):
            return []
        return list(self.adjacent[v])

    #出次数
    def out_degree(self,v):
        if not self.vertex_exist(v):
            return 0

        return len(self.adjacent_out[v])

    #入次数
    def in_degree(self,v):
        if not self.vertex_exist(v):
            return 0

        return len(self.adjacent_in[v])

    #次数
    def degree(self,v):
        if not self.vertex_exist(v):
            return 0

        return self.out_degree(v)-self.in_degree(v)

    #頂点数
    def vertex_count(self):
        return len(self.vertex)

    #辺数
    def edge_count(self):
        return self.edge_number

    #頂点vを含む連結成分
    def connected_component(self,v):
        pass

def Flow(D,source,sink,Mode=False):
    """Source sからSink tへの最大流問題を解く.
    Mode:
    True---各頂点の流し方も返す
    False---解答のみ
    """
    import sys
    sys.setrecursionlimit(10**6)

    s,t=source,sink

    H={v:[] for v in D.vertex}

    for u in D.vertex:
        for v in D.adjacent_out[u]:
            F=[v,D.adjacent_out[u][v],None]
            F[2]=B=[u,0,F]
            H[u].append(F)
            H[v].append(B)

    def dfs(v,t,f):
        if v==t:
            return f

        U[v]=True
        for e in H[v]:
            w,cap,inv=e

            if cap and (not U[w]):
                d=dfs(w,t,min(f,cap))
                if d:
                    e[1]-=d
                    inv[1]+=d
                    return d
        return 0

    inf=float("inf")
    f=inf
    flow=0
    while f:
        U={v:False for v in D.vertex}
        f=dfs(s,t,inf)
        flow+=f

    if Mode:
        R={}
        for v in D.vertex:
            R[v]={}
            for S in H[v]:
                w=S[0]
                if w in D.adjacent_out[v]:
                    R[v][w]=S[-1][1]

        return flow,R
    else:
        return flow
#================================================
N,M=map(int,input().split())

V=[(i,j) for i in range(1,N+1) for j in range(1,M+1)]
D=Weigthed_Digraph(V)

S=[""]*(N+2)
S[0]=S[-1]="*"*(M+2)

for i in range(1,N+1):
    S[i]="*"+input()+"*"

H=[(0,1),(0,-1),(1,0),(-1,0)]
for y in range(1,N+1):
    for x in range(1,M+1):
        if S[y][x]!="." or (x+y)%2==0:
            continue

        for (a,b) in H:
            if S[y+a][x+b]==".":
                D.add_edge((y,x),(y+a,x+b),1)

for y in range(1,N+1):
    for x in range(1,M+1):
        if S[y][x]==".":
            if (x+y)%2:
                D.add_edge("s",(y,x),1)
            else:
                D.add_edge((y,x),"t",1)

flow,F=Flow(D,"s","t",True)

U=[[S[j][i] for i in range(M+2)] for j in range(N+2)]

for y in range(1,N+1):
    for x in range(1,M+1):
        if S[y][x]=="#":
            continue

        for C in F[(y,x)]:
            try:
                q,p=C
                if F[(y,x)][(q,p)]:
                    if (y+1,x)==(q,p):
                        U[y][x]  ="v"
                        U[y+1][x]="^"
                    elif (y-1,x)==(q,p):
                        U[y][x]  ="^"
                        U[y-1][x]="v"
                    elif (y,x+1)==(q,p):
                        U[y][x]  =">"
                        U[y][x+1]="<"
                    elif (y,x-1)==(q,p):
                        U[y][x]  ="<"
                        U[y][x-1]=">"
            except:
                pass

print(flow)
Y=["".join(U[k][1:-1]) for k in range(1,N+1)]
print("\n".join(Y))