Buggy python submission (verdict: Time Limit Exceeded):
# -*- coding: utf-8 -*-
h,w = map(int, input().split())
sf = [input() for _ in range(h)]

def check(c1,c2):
    st = [(c1[0],c1[1],"#")]
    visited = [[False for _ in range(w)] for _ in range(h)]
    while len(st)>0:
        s = st.pop()
        visited[s[0]][s[1]] = True
        if s[0]==c2[0] and s[1]==c2[1]:
            return True
        for d in [[1,0],[0,1],[-1,0],[0,-1]]:
            dh = s[0]+d[0]
            dw = s[1]+d[1]
            if h>dh>=0 and w>dw>=0:
                if s[2]=="#" and sf[dh][dw]=="." and not visited[dh][dw]:
                    st.append((dh,dw,"."))
                elif s[2]=="." and sf[dh][dw]=="#" and not visited[dh][dw]:
                    st.append((dh,dw,"#"))
    return False

def candidate(hi,wi):
    for d in [[1,0],[0,1],[-1,0],[0,-1]]:
        dh = hi+d[0]
        dw = wi+d[1]
        if h>dh>=0 and w>dw>=0 and sf[hi][wi]!=sf[dh][dw]:
            return True
    return False

p1 = []
p2 = []
for hi in range(h):
    for wi in range(w):
        if not candidate(hi,wi):
            continue
        if sf[hi][wi]=="#":
            p1.append((hi,wi))
        else:
            p2.append((hi,wi))

res = 0
for c1 in p1:
    for c2 in p2:
        if check(c1,c2):
            res += 1

# for hi1 in range(h):
#     for wi1 in range(w):
#         if not candidate(hi1,wi1):
#             continue
#         if sf[hi1][wi1]==".":
#             continue
#         for hi2 in range(h):
#             for wi2 in range(w):
#                 if hi1==hi2 and wi1==wi2:
#                     continue
#                 if not candidate(hi2,wi2):
#                     continue
#                 if sf[hi2][wi2]=="#":
#                     continue
#
#                 # print("check",(hi1,wi1), (hi2,wi2))
#                 if check((hi1,wi1),(hi2,wi2)):
#                     # print((hi1,wi1), (hi2,wi2))
#                     res += 1

print(res)


Fixed submission:
# -*- coding: utf-8 -*-
h,w = map(int, input().split())
sf = [input() for _ in range(h)]

def candidate(hi,wi):
    for d in [[1,0],[0,1],[-1,0],[0,-1]]:
        dh = hi+d[0]
        dw = wi+d[1]
        if h>dh>=0 and w>dw>=0 and sf[hi][wi]!=sf[dh][dw]:
            return True
    return False

csf = [[False for _ in range(w)] for _ in range(h)]
for hi in range(h):
    for wi in range(w):
        csf[hi][wi] = candidate(hi,wi)
res = 0
used = [[False for _ in range(w)] for _ in range(h)]
for hi in range(h):
    for wi in range(w):
        if used[hi][wi]:
            continue
        st = [(hi,wi,sf[hi][wi])]
        nb = 0
        nw = 0
        # print("===")
        while len(st)>0:
            s = st.pop()
            # print(s)
            if csf[s[0]][s[1]] and not used[s[0]][s[1]]:
                used[s[0]][s[1]] = True
                if s[2] == "#":
                    nb += 1
                else:
                    nw += 1
                for d in [[1,0],[0,1],[-1,0],[0,-1]]:
                    dh = s[0]+d[0]
                    dw = s[1]+d[1]
                    if h>dh>=0 and w>dw>=0 and csf[dh][dw] and not used[dh][dw] and sf[s[0]][s[1]]!=sf[dh][dw]:
                        st.append((dh,dw,sf[dh][dw]))
        res += nb*nw
print(res)

Buggy python submission (verdict: Time Limit Exceeded):
# -*- coding: utf-8 -*-
h,w = map(int, input().split())
sf = [input() for _ in range(h)]

def check(c1,c2):
    st = [(c1[0],c1[1],"#")]
    visited = [[False for _ in range(w)] for _ in range(h)]
    while len(st)>0:
        s = st.pop()
        visited[s[0]][s[1]] = True
        if s[0]==c2[0] and s[1]==c2[1]:
            return True
        for d in [[1,0],[0,1],[-1,0],[0,-1]]:
            dh = s[0]+d[0]
            dw = s[1]+d[1]
            if h>dh>=0 and w>dw>=0:
                if s[2]=="#" and sf[dh][dw]=="." and not visited[dh][dw]:
                    st.append((dh,dw,"."))
                elif s[2]=="." and sf[dh][dw]=="#" and not visited[dh][dw]:
                    st.append((dh,dw,"#"))
    return False

def candidate(hi,wi):
    for d in [[1,0],[0,1],[-1,0],[0,-1]]:
        dh = hi+d[0]
        dw = wi+d[1]
        if h>dh>=0 and w>dw>=0 and sf[hi][wi]!=sf[dh][dw]:
            return True
    return False

res = 0
for hi1 in range(h):
    for wi1 in range(w):
        if not candidate(hi1,wi1):
            continue
        if sf[hi1][wi1]==".":
            continue
        for hi2 in range(h):
            for wi2 in range(w):
                if hi1==hi2 and wi1==wi2:
                    continue
                if not candidate(hi2,wi2):
                    continue
                if sf[hi2][wi2]=="#":
                    continue

                # print("check",(hi1,wi1), (hi2,wi2))
                if check((hi1,wi1),(hi2,wi2)):
                    # print((hi1,wi1), (hi2,wi2))
                    res += 1

print(res)


Fixed submission:
# -*- coding: utf-8 -*-
h,w = map(int, input().split())
sf = [input() for _ in range(h)]

def candidate(hi,wi):
    for d in [[1,0],[0,1],[-1,0],[0,-1]]:
        dh = hi+d[0]
        dw = wi+d[1]
        if h>dh>=0 and w>dw>=0 and sf[hi][wi]!=sf[dh][dw]:
            return True
    return False

csf = [[False for _ in range(w)] for _ in range(h)]
for hi in range(h):
    for wi in range(w):
        csf[hi][wi] = candidate(hi,wi)
res = 0
used = [[False for _ in range(w)] for _ in range(h)]
for hi in range(h):
    for wi in range(w):
        if used[hi][wi]:
            continue
        st = [(hi,wi,sf[hi][wi])]
        nb = 0
        nw = 0
        # print("===")
        while len(st)>0:
            s = st.pop()
            # print(s)
            if csf[s[0]][s[1]] and not used[s[0]][s[1]]:
                used[s[0]][s[1]] = True
                if s[2] == "#":
                    nb += 1
                else:
                    nw += 1
                for d in [[1,0],[0,1],[-1,0],[0,-1]]:
                    dh = s[0]+d[0]
                    dw = s[1]+d[1]
                    if h>dh>=0 and w>dw>=0 and csf[dh][dw] and not used[dh][dw] and sf[s[0]][s[1]]!=sf[dh][dw]:
                        st.append((dh,dw,sf[dh][dw]))
        res += nb*nw
print(res)