#include <bits/stdc++.h>
using namespace std;
template <typename T>
T gcd(T x, T y) {
  while (y > 0) {
    x %= y;
    swap(x, y);
  }
  return x;
}
template <class _T>
inline _T sqr(const _T &x) {
  return x * x;
}
template <class _T>
inline string tostr(const _T &a) {
  ostringstream os("");
  os << a;
  return os.str();
}
const long double PI = 3.1415926535897932384626433832795L;
template <typename T>
inline void input(T &a) {
  static int c;
  a = 0;
  while (!isdigit(c = getchar()) && c != '-') {
  }
  char neg = 0;
  if (c == '-') {
    neg = 1;
    c = getchar();
  }
  while (isdigit(c)) {
    a = 10 * a + c - '0';
    c = getchar();
  }
  if (neg) a = -a;
}
template <typename T = int>
inline T nxt() {
  T res;
  input(res);
  return res;
}
struct S {
  int x, y, cost;
};
struct Edge {
  int from, to, cap, flow;
  long long len;
};
const int N = 22;
char s[N][N + 1];
vector<S> le;
vector<S> ri;
const int NM = N * N;
int dist[NM][NM];
int qu[NM];
char used[NM];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
long long distle[NM][NM];
long long distri[NM][NM];
vector<Edge> edges;
vector<int> g[4 * NM + 5];
int us[4 * NM + 5];
int phase = 1;
int que[4 * NM + 5];
int p[4 * NM + 5];
void addEdge(int from, int to, int cap, long long len) {
  g[from].push_back(edges.size());
  edges.push_back(Edge{from, to, cap, 0, len});
  g[to].push_back(edges.size());
  edges.push_back(Edge{to, from, 0, 0, len});
}
int vertSize;
int ptr[5 * NM + 5];
int ddd[5 * NM + 5];
bool bfs(int s, int t, long long len) {
  ++phase;
  int q1 = 0, q2 = 0;
  que[q2++] = s;
  us[s] = phase;
  ddd[s] = 0;
  p[s] = -1;
  while (q1 < q2) {
    int v = que[q1++];
    for (int ed : g[v]) {
      Edge &e = edges[ed];
      if (e.len > len) break;
      if (e.cap > e.flow) {
        if (us[e.to] != phase) {
          us[e.to] = phase;
          que[q2++] = e.to;
          p[e.to] = ed;
          ddd[e.to] = ddd[v] + 1;
        }
      }
    }
  }
  return us[t] == phase;
}
int dfs(int v, int t, int flow, long long len) {
  if (!flow) return 0;
  if (v == t) return flow;
  for (; ptr[v] < (int)g[v].size(); ++ptr[v]) {
    int id = g[v][ptr[v]], to = edges[id].to;
    if (edges[id].len > len) {
      break;
    }
    if (ddd[to] != ddd[v] + 1) continue;
    int pushed = dfs(to, t, min(flow, edges[id].cap - edges[id].flow), len);
    if (pushed) {
      edges[id].flow += pushed;
      edges[id ^ 1].flow -= pushed;
      return pushed;
    }
  }
  return 0;
}
int dinic(int s, int t, long long len) {
  int flow = 0;
  for (;;) {
    if (!bfs(s, t, len)) break;
    memset(ptr, 0, vertSize * sizeof(int));
    while (int pushed = dfs(s, t, 1000, len)) flow += pushed;
  }
  return flow;
}
void clearFlow(long long len) {
  for (int i = 0; i < vertSize; ++i) {
    for (int ed : g[i]) {
      if (edges[ed].len > len) {
        break;
      }
      edges[ed].flow = 0;
    }
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int n, m, B, G;
  n = nxt();
  m = nxt();
  B = nxt();
  G = nxt();
  if (abs(B - G) != 1) {
    puts("-1");
    return 0;
  }
  int emptyCell = 0;
  for (int i = 0; i < n; ++i) {
    scanf("%s", s[i]);
    for (int j = 0; j < m; ++j) {
      emptyCell += s[i][j] == '.';
    }
  }
  if ((B + G + 1) / 2 > emptyCell) {
    puts("-1");
    return 0;
  }
  {
    int r = nxt() - 1;
    int c = nxt() - 1;
    int t = nxt();
    if (B < G) {
      le.push_back(S{r, c, t});
    } else {
      ri.push_back(S{r, c, t});
    }
  }
  for (int i = 0; i < B; ++i) {
    int r = nxt() - 1;
    int c = nxt() - 1;
    int t = nxt();
    le.push_back(S{r, c, t});
  }
  for (int i = 0; i < G; ++i) {
    int r = nxt() - 1;
    int c = nxt() - 1;
    int t = nxt();
    ri.push_back(S{r, c, t});
  }
  memset(dist, 0x3f, sizeof(dist));
  int inf = dist[0][0];
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      int st = i * m + j;
      if (s[i][j] == '#') continue;
      dist[st][st] = 0;
      int q1 = 0, q2 = 0;
      qu[q2++] = st;
      memset(used, 0, sizeof(used));
      used[st] = 1;
      while (q1 < q2) {
        int id = qu[q1++];
        int vx = id / m;
        int vy = id % m;
        for (int k = 0; k < 4; ++k) {
          int x = vx + dx[k];
          int y = vy + dy[k];
          if (x < 0 || x >= n || y < 0 || y >= m) continue;
          if (s[x][y] == '#') continue;
          int nid = x * m + y;
          if (!used[nid]) {
            used[nid] = 1;
            qu[q2++] = nid;
            dist[st][nid] = dist[st][id] + 1;
          }
        }
      }
    }
  }
  long long maxdist = 0;
  for (int i = 0; i < int(le.size()); ++i) {
    int ii = le[i].x * m + le[i].y;
    for (int jj = 0; jj < n * m; ++jj) {
      if (dist[ii][jj] != inf) {
        distle[i][jj] = dist[ii][jj] * 1ll * le[i].cost;
        maxdist = max(maxdist, distle[i][jj]);
      } else {
        distle[i][jj] = LLONG_MAX;
      }
    }
  }
  for (int i = 0; i < int(ri.size()); ++i) {
    int ii = ri[i].x * m + ri[i].y;
    for (int jj = 0; jj < n * m; ++jj) {
      if (dist[ii][jj] != inf) {
        distri[i][jj] = dist[ii][jj] * 1ll * ri[i].cost;
        maxdist = max(maxdist, distri[i][jj]);
      } else {
        distri[i][jj] = LLONG_MAX;
      }
    }
  }
  for (int i = 0; i < n * m; ++i) {
    addEdge(2 * i, 2 * i + 1, 1, 0);
  }
  int curv = 2 * n * m;
  int source = curv + le.size() + ri.size();
  int sink = curv + le.size() + ri.size() + 1;
  for (int i = 0; i < (int)le.size(); ++i) {
    for (int j = 0; j < n * m; ++j) {
      if (distle[i][j] != LLONG_MAX) addEdge(curv + i, 2 * j, 1, distle[i][j]);
    }
    addEdge(source, curv + i, 1, 0);
  }
  curv += le.size();
  for (int i = 0; i < int(ri.size()); ++i) {
    for (int j = 0; j < n * m; ++j) {
      if (distri[i][j] != LLONG_MAX)
        addEdge(2 * j + 1, curv + i, 1, distri[i][j]);
    }
    addEdge(curv + i, sink, 1, 0);
  }
  for (int i = 0; i <= sink; ++i) {
    sort((g[i]).begin(), (g[i]).end(),
         [&](int l, int r) { return edges[l].len < edges[r].len; });
  }
  long long l = 0, r = maxdist;
  int needFlow = le.size();
  vertSize = sink + 1;
  while (l < r) {
    long long mid = (l + r) >> 1;
    int flow = dinic(source, sink, mid);
    clearFlow(mid);
    if (flow < needFlow) {
      l = mid + 1;
    } else {
      r = mid;
    }
  }
  int flow = dinic(source, sink, l);
  if (flow != needFlow) {
    cout << "-1" << endl;
    return 0;
  }
  cout << l << endl;
  return 0;
};
