Buggy python submission (verdict: Time Limit Exceeded):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from itertools import accumulate #list(accumulate(A))

H, W = mi()
S = [li() for _ in range(H)]
flag = [[0]*W for _ in range(H)]
flag_odd = [[0]*W for _ in range(H)]
odd_l = []

for i in range(H):
    for j in range(W):
        if S[i][j] % 2:
            odd_l.append([i, j])
            flag_odd[i][j] = 1

odd_l = sorted(odd_l, key = lambda x:(x[0], x[1]))

#print(odd_l)
num_odd = len(odd_l)

ans = []
for si, sj in odd_l[:(num_odd//2)*2]:
    if not flag_odd[si][sj]:
        continue
    flag_odd[si][sj] = 0
    flag[si][sj] = 1
    while True:
        if si+1 < H and not flag[si+1][sj]:
            si += 1
            flag[si][sj] = 1
            ans.append([si-1, sj, si, sj])
        if sj+1 < W and not flag[si][sj+1]:
            sj += 1
            flag[si][sj] = 1
            ans.append([si, sj-1, si, sj])
        if flag_odd[si][sj] == 1:
            flag_odd[si][sj] = 0
            break

print(len(ans))
for si, sj, ti, tj in ans:
    print(si+1, sj+1, ti+1, tj+1)

Fixed submission:
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from itertools import accumulate #list(accumulate(A))

H, W = mi()
S = [li() for _ in range(H)]
f = 0
ans = []

for j in range(W):
    if not j%2:
        for i in range(H):
            if f:
                ans.append([pi, pj, i+1, j+1])
            if S[i][j] % 2:
                f = 1 - f
            pi, pj = i+1, j+1
    if j%2:
        for i in reversed(range(H)):
            if f:
                ans.append([pi, pj, i+1, j+1])
            if S[i][j] % 2:
                f = 1 - f
            pi, pj = i+1, j+1


N = len(ans)
print(N)
for i in range(N):
    print(ans[i][0], ans[i][1], ans[i][2], ans[i][3])

Buggy python submission (verdict: Time Limit Exceeded):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from itertools import accumulate #list(accumulate(A))

H, W = mi()
S = [li() for _ in range(H)]
flag = [[0]*W for _ in range(H)]
flag_odd = [[0]*W for _ in range(H)]
odd_l = []

for i in range(H):
    for j in range(W):
        if S[i][j] % 2:
            odd_l.append([i, j, i+j])
            flag_odd[i][j] = 1

odd_l = sorted(odd_l, key = lambda x:x[2])

#print(odd_l)
num_odd = len(odd_l)

ans = []
for si, sj, _ in odd_l[:(num_odd//2)*2]:
    #si, sj = odd_l[2*i][0], odd_l[2*i][1]
    #ti, tj = odd_l[2*i+1][0], odd_l[2*i+1][1]
    if not flag_odd[si][sj]:
        continue
    flag_odd[si][sj] = 0
    flag[si][sj] = 1
    while True:
        if si+1 < H and not flag[si+1][sj]:
            si += 1
            flag[si][sj] = 1
            ans.append([si-1, sj, si, sj])
        if sj+1 < W and not flag[si][sj+1]:
            sj += 1
            flag[si][sj] = 1
            ans.append([si, sj-1, si, sj])
        if flag_odd[si][sj] == 1:
            flag_odd[si][sj] = 0
            break

print(len(ans))
for si, sj, ti, tj in ans:
    print(si+1, sj+1, ti+1, tj+1)

Fixed submission:
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from itertools import accumulate #list(accumulate(A))

H, W = mi()
S = [li() for _ in range(H)]
f = 0
ans = []

for j in range(W):
    if not j%2:
        for i in range(H):
            if f:
                ans.append([pi, pj, i+1, j+1])
            if S[i][j] % 2:
                f = 1 - f
            pi, pj = i+1, j+1
    if j%2:
        for i in reversed(range(H)):
            if f:
                ans.append([pi, pj, i+1, j+1])
            if S[i][j] % 2:
                f = 1 - f
            pi, pj = i+1, j+1


N = len(ans)
print(N)
for i in range(N):
    print(ans[i][0], ans[i][1], ans[i][2], ans[i][3])