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:
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---解答のみ
    """
    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
#================================================
from sys import setrecursionlimit
setrecursionlimit(10**5)

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))

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---解答のみ
    """
    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]="^"
                        flag=False
                    elif (y-1,x)==(q,p):
                        U[y][x]  ="^"
                        U[y-1][x]="v"
                        flag=False
                    elif (y,x+1)==(q,p):
                        U[y][x]  =">"
                        U[y][x+1]="<"
                        flag=False
                    elif (y,x-1)==(q,p):
                        U[y][x]  ="<"
                        U[y][x-1]=">"
                        flag=False
            except:
                pass

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

Submission status: Runtime Error

Solution code:
import networkx as nx
from networkx.algorithms.bipartite import hopcroft_karp_matching

n, m = map(int, input().split())

def inside(x, y):
	if 0 <= x < n and 0 <= y < m:
		return True
	else:
		return False

DI = [1, 0, -1, 0]
DJ = [0, 1, 0, -1]

a = [list(input()) for _ in range(n)]
g = nx.Graph()
g.add_nodes_from(range(n*m))
zero = True
for i in range(n):
	for j in range(m):
		if a[i][j] == "#":
			continue
		if (i+j)%2 == 0:
			for k in range(4):
				di, dj = i+DI[k], j+DJ[k]
				if inside(di, dj) and a[di][dj] == ".":
					zero = False
					g.add_edge(i*m+j, di*m+dj)
if zero:
	print(0)
else:
	h = hopcroft_karp_matching(g, top_nodes = {i for i in range(0, n*m, 2)})
	print(len(h)//2)
	for fr, to in h.items():
		i0, j0 = fr//m, fr%m
		i1, j1 = to//m, to%m
		if a[i0][j0] != ".":
			continue
		if i1 == i0+1:
			a[i0][j0] = "v"
			a[i1][j1] = "^"
		elif i1 == i0-1:
			a[i0][j0] = "^"
			a[i1][j1] = "v"
		elif j1 == j0+1:
			a[i0][j0] = ">"
			a[i1][j1] = "<"
		else:
			a[i0][j0] = "<"
			a[i1][j1] = ">"
print(*["".join(x) for x in a], sep="\n")

Submission status: Runtime Error

Solution code:
import networkx as nx
from networkx.algorithms.bipartite import hopcroft_karp_matching

n, m = map(int, input().split())

def inside(x, y):
	if 0 <= x < n and 0 <= y < m:
		return True
	else:
		return False

DI = [1, 0, -1, 0]
DJ = [0, 1, 0, -1]

a = [list(input()) for _ in range(n)]
g = nx.Graph()
for i in range(0, n*m, 2):
	g.add_node(i, bipartite=0)
for i in range(1, n*m, 2):
	g.add_node(i, bipartite=1)
zero = True
for i in range(n):
	for j in range(m):
		if a[i][j] == "#":
			continue
		if (i+j)%2 == 0:
			for k in range(4):
				di, dj = i+DI[k], j+DJ[k]
				if inside(di, dj) and a[di][dj] == ".":
					zero = False
					g.add_edge(i*m+j, di*m+dj)
if zero:
	print(0)
else:
	h = hopcroft_karp_matching(g, top_nodes = {i for i in range(0, n*m, 2)})
	print(len(h)//2)
	for fr, to in h.items():
		i0, j0 = fr//m, fr%m
		i1, j1 = to//m, to%m
		if a[i0][j0] != ".":
			continue
		if i1 == i0+1:
			a[i0][j0] = "v"
			a[i1][j1] = "^"
		elif i1 == i0-1:
			a[i0][j0] = "^"
			a[i1][j1] = "v"
		elif j1 == j0+1:
			a[i0][j0] = ">"
			a[i1][j1] = "<"
		else:
			a[i0][j0] = "<"
			a[i1][j1] = ">"
print(*["".join(x) for x in a], sep="\n")

Submission status: Runtime Error

Solution code:
import networkx as nx
from networkx.algorithms.flow import dinitz

n, m = map(int, input().split())

def inside(x, y):
	if 0 <= x < n and 0 <= y < m:
		return True
	else:
		return False

DI = [1, 0, -1, 0]
DJ = [0, 1, 0, -1]

a = [list(input()) for _ in range(n)]
S, T = n*m, n*m+1
g = nx.DiGraph()
for i in range(n):
	for j in range(m):
		if a[i][j] == "#":
			continue
		if (i+j)%2:
			g.add_edge(i*m+j, T, capacity=1)
		else:
			g.add_edge(S, i*m+j, capacity=1)
			for k in range(4):
				di, dj = i+DI[k], j+DJ[k]
				if inside(di, dj) and a[di][dj] == ".":
					g.add_edge(i*m+j, di*m+dj, capacity=1)
r = dinitz(g, S, T)
print(r.graph["flow_value"])
#print(*r.edges)
for i0 in range(n):
	for j0 in range(m):
		if (i0+j0)%2 or a[i0][j0] != ".":
			continue
		for k in range(4):
			i1, j1 = i0+DI[k], j0+DJ[k]
			if not inside(i1, j1) or a[i1][j1] != ".":
				continue
			#print(i0, j0, i1, j1)
			if r[i0*m+j0][i1*m+j1]["flow"] != 1:
				continue
			if i1 == i0+1:
				a[i0][j0] = "v"
				a[i1][j1] = "^"
			elif i1 == i0-1:
				a[i0][j0] = "^"
				a[i1][j1] = "v"
			elif j1 == j0+1:
				a[i0][j0] = ">"
				a[i1][j1] = "<"
			else:
				a[i0][j0] = "<"
				a[i1][j1] = ">"
print(*["".join(x) for x in a], sep="\n")

Submission status: Runtime Error

Solution code:
import networkx as nx
from networkx.algorithms.flow import dinitz

n, m = map(int, input().split())

def inside(x, y):
	if 0 <= x < n and 0 <= y < m:
		return True
	else:
		return False

DI = [1, 0, -1, 0]
DJ = [0, 1, 0, -1]

a = [list(input()) for _ in range(n)]
S, T = n*m, n*m+1
g = nx.DiGraph()
for i in range(n):
	for j in range(m):
		if a[i][j] == "#":
			continue
		if (i+j)%2:
			g.add_edge(i*m+j, T, capacity=1)
		else:
			g.add_edge(S, i*m+j, capacity=1)
			for k in range(4):
				di, dj = i+DI[k], j+DJ[k]
				if inside(di, dj) and a[di][dj] == ".":
					g.add_edge(i*m+j, di*m+dj, capacity=1)
r = dinitz(g, S, T)
print(r.graph["flow_value"])
#print(*r.edges)
for e in r.edges:
	fr, to = e
	#print(fr, to)
	if fr == S or to == T or r[fr][to]["flow"] < 1:
		continue
	i0, j0 = fr//m, fr%m
	i1, j1 = to//m, to%m
	if i1 == i0+1:
		a[i0][j0] = "v"
		a[i1][j1] = "^"
	elif i1 == i0-1:
		a[i0][j0] = "^"
		a[i1][j1] = "v"
	elif j1 == j0+1:
		a[i0][j0] = ">"
		a[i1][j1] = "<"
	else:
		a[i0][j0] = "<"
		a[i1][j1] = ">"
print(*["".join(x) for x in a], sep="\n")

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
        dq = deque([s])
        self.level[s] = 0
        while dq:
            v = dq.popleft()
            nlevel = self.level[v]+1
            for w,cap,_ in self.graph[v]:
                if cap and self.level[w] is None:
                    self.level[w] = nlevel
                    dq.append(w)
        return self.level[t] is not None
    
    def dfs(self,s,v,f):
        if v == s:
            return f
        for rev in self.it[v]:
            w,_,e = rev
            cap = e[1]
            if cap and self.level[w] is not None:
                if self.level[v] > self.level[w]:
                    d = self.dfs(s,w,min(f,cap))
                    if d:
                        e[1] -= d
                        rev[1] += d
                        return d
        return 0
    
    def flow(self,s,t,flow_limit=float('inf')):
        flow = 0
        while self.bfs(s,t):
            *self.it, = map(iter,self.graph)
            f = flow_limit
            while f:
                f = self.dfs(s,t,flow_limit-flow)
                flow += f
        return flow

    def min_cut(self,s):
        visited = [False]*self.N
        dq = deque([s])
        while dq:
            v = dq.pop()
            visited[v] = True
            for w,cap,_ in self.graph[v]:
                if cap and not visited[w]:
                    dq.append(w)
import sys
input = sys.stdin.buffer.readline().rstrip

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
        dq = deque([s])
        self.level[s] = 0
        while dq:
            v = dq.popleft()
            nlevel = self.level[v]+1
            for w,cap,_ in self.graph[v]:
                if cap and self.level[w] is None:
                    self.level[w] = nlevel
                    dq.append(w)
        return self.level[t] is not None
    
    def dfs(self,s,v,f):
        if v == s:
            return f
        for rev in self.it[v]:
            w,_,e = rev
            cap = e[1]
            if cap and self.level[w] is not None:
                if self.level[v] > self.level[w]:
                    d = self.dfs(s,w,min(f,cap))
                    if d:
                        e[1] -= d
                        rev[1] += d
                        return d
        return 0
    
    def flow(self,s,t,flow_limit=float('inf')):
        flow = 0
        while self.bfs(s,t):
            *self.it, = map(iter,self.graph)
            f = flow_limit
            while f:
                f = self.dfs(s,t,flow_limit-flow)
                flow += f
        return flow

    def min_cut(self,s):
        visited = [False]*self.N
        dq = deque([s])
        while dq:
            v = dq.pop()
            visited[v] = True
            for w,cap,_ in self.graph[v]:
                if cap and not visited[w]:
                    dq.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,10**9))
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
        dq = deque([s])
        self.level[s] = 0
        while dq:
            v = dq.popleft()
            nlevel = self.level[v]+1
            for w,cap,_ in self.graph[v]:
                if cap and self.level[w] is None:
                    self.level[w] = nlevel
                    dq.append(w)
        return self.level[t] is not None
    
    def dfs(self,s,v,f):
        if v == s:
            return f
        for rev in self.it[v]:
            w,_,e = rev
            cap = e[1]
            if cap and self.level[w] is not None:
                if self.level[v] > self.level[w]:
                    d = self.dfs(s,w,min(f,cap))
                    if d:
                        e[1] -= d
                        rev[1] += d
                        return d
        return 0
    
    def flow(self,s,t,flow_limit=float('inf')):
        flow = 0
        while self.bfs(s,t):
            *self.it, = map(iter,self.graph)
            f = flow_limit
            while f:
                f = self.dfs(s,t,flow_limit-flow)
                flow += f
        return flow

    def min_cut(self,s):
        visited = [False]*self.N
        dq = deque([s])
        while dq:
            v = dq.pop()
            visited[v] = True
            for w,cap,_ in self.graph[v]:
                if cap and not visited[w]:
                    dq.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.max_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:
import networkx as nx

R, C = [int(x) for x in input().split()]
grid = [list(input()) for r in range(R)]


def pack(r, c):
    return r * C + c


graph = nx.Graph()
for r in range(R - 1):
    for c in range(C - 1):
        if grid[r][c] == grid[r + 1][c] == ".":
            graph.add_edge(pack(r, c), pack(r + 1, c))
        if grid[r][c] == grid[r][c + 1] == ".":
            graph.add_edge(pack(r, c), pack(r, c + 1))

matching = nx.bipartite.maximum_matching(graph)

count = 0
for u, v in matching.items():
    if u > v:
        assert matching[v] == u
        r1, c1 = divmod(u, C)
        r2, c2 = divmod(v, C)
        if r1 == r2:
            if c1 > c2:
                c1, c2 = c2, c1
            grid[r1][c1], grid[r2][c2] = ">", "<"
        elif c1 == c2:
            if r1 > r2:
                r1, r2 = r2, r1
            grid[r1][c1] = "v"
            grid[r2][c2] = "^"
        count += 1

print(count)
for row in grid:
    print("".join(row))