#include <bits/stdc++.h>
using namespace std;
void testGen() {
  freopen("biginput2.txt", "w", stdout);
  int n = 14;
  cout << n << " " << n << " " << n * n << " " << n * n - 1 << endl;
  for (auto repeat_var = 0; repeat_var < n; ++repeat_var) {
    for (auto repeat_var = 0; repeat_var < n; ++repeat_var) {
      cout << ".";
    }
    cout << endl;
  }
  for (auto repeat_var = 0; repeat_var < 2 * n * n; ++repeat_var) {
    cout << 1 << " " << 1 << " " << 1 << endl;
  }
  fclose(stdout);
}
struct Network {
  struct Edge {
    int u, v;
    int f, c;
  };
  vector<Edge> edgeList;
  vector<vector<int> > adj;
  void addEdge(int u, int v, int c) {
    Edge e = {u, v, 0, c};
    adj[u].push_back((int)edgeList.size());
    adj[v].push_back((int)edgeList.size());
    edgeList.push_back(e);
  }
  int n() { return (int)adj.size(); }
  void resetFlow() {
    for (auto &pe : edgeList) pe.f = 0;
  }
  void init(int n) {
    edgeList.clear();
    adj.resize(n);
    for (auto &au : adj) au.clear();
  }
  Network(int n) { init(n); }
};
class Dinic {
  Network &g;
  int s, t;
  vector<int> dist;
  vector<bool> block;
  bool computeDist() {
    queue<int> q;
    q.push(t);
    fill(dist.begin(), dist.end(), -1);
    dist[t] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (auto pi : g.adj[u]) {
        Network::Edge &e = g.edgeList[pi];
        if (e.v == u && e.f < e.c) {
          if (dist[e.u] == -1) {
            dist[e.u] = dist[u] + 1;
            q.push(e.u);
            if (e.u == s) return true;
          }
        } else if (e.u == u && e.f > 0) {
          if (dist[e.v] == -1) {
            dist[e.v] = dist[u] + 1;
            q.push(e.v);
            if (e.v == s) return true;
          }
        }
      }
    }
    return dist[s] != -1;
  }
  int findAugmentingPath(int u, int delta) {
    if (u == t) return delta;
    int inc;
    for (auto pi : g.adj[u]) {
      Network::Edge &e = g.edgeList[pi];
      if (e.u == u && e.f < e.c) {
        if (!block[e.v] && dist[u] == dist[e.v] + 1 &&
            (inc = findAugmentingPath(e.v, min(delta, e.c - e.f)))) {
          e.f += 1 * inc;
          return inc;
        }
      } else if (e.v == u && e.f > 0) {
        if (!block[e.u] && dist[u] == dist[e.u] + 1 &&
            (inc = findAugmentingPath(e.u, min(delta, e.f)))) {
          e.f += -1 * inc;
          return inc;
        }
      }
    }
    block[u] = true;
    return 0;
  }

 public:
  int totalFlow;
  Dinic(Network &g, int s, int t) : g(g), s(s), t(t) {
    g.resetFlow();
    totalFlow = 0;
    dist.resize(g.n());
    block.resize(g.n());
  }
  int run() {
    while (computeDist()) {
      fill(block.begin(), block.end(), false);
      while (int inc = findAugmentingPath(s, 2E9L)) totalFlow += inc;
    }
    return totalFlow;
  }
};
char board[23][23];
int row[2][23 * 23], col[2][23 * 23], speed[2][23 * 23];
int nRow, nCol, nMale, nFemale;
int dist[23][23][23][23];
int squareID[23][23], nSquare = 0;
long long best[2][23 * 23][23][23];
int idCount[2];
void addScay(int type, int r, int c, int t) {
  r--;
  c--;
  row[type][idCount[type]] = r;
  col[type][idCount[type]] = c;
  speed[type][idCount[type]] = t;
  idCount[type]++;
}
int main() {
  cin >> nRow >> nCol >> nMale >> nFemale;
  if ((nMale + nFemale) % 2 == 0) {
    cout << -1;
    return 0;
  }
  if (abs(nMale - nFemale) >= 2) {
    cout << -1;
    return 0;
  }
  for (int i = 0; i < nRow; ++i) {
    cin >> board[i];
    assert(strlen(board[i]) == nCol);
  }
  idCount[0] = idCount[1] = 0;
  int r, c, t;
  cin >> r >> c >> t;
  if (nMale == nFemale + 1) {
    addScay(1, r, c, t);
  } else {
    addScay(0, r, c, t);
  }
  for (int i = 0; i < nMale; ++i) {
    cin >> r >> c >> t;
    addScay(0, r, c, t);
  }
  for (int i = 0; i < nFemale; ++i) {
    cin >> r >> c >> t;
    addScay(1, r, c, t);
  }
  if (nMale == nFemale + 1) {
    nFemale++;
  } else {
    nMale++;
  }
  for (int r = 0; r < nRow; ++r)
    for (int c = 0; c < nCol; ++c)
      for (int r2 = 0; r2 < nRow; ++r2)
        for (int c2 = 0; c2 < nCol; ++c2) {
          dist[r][c][r2][c2] = 2E9L;
          if (r2 == r && c2 == c) {
            dist[r][c][r2][c2] = 0;
          } else if (abs(r2 - r) + abs(c2 - c) == 1) {
            if (board[r][c] != '#' && board[r2][c2] != '#') {
              dist[r][c][r2][c2] = 1;
            }
          }
        }
  for (int rk = 0; rk < nRow; ++rk)
    for (int ck = 0; ck < nCol; ++ck)
      for (int r = 0; r < nRow; ++r)
        for (int c = 0; c < nCol; ++c)
          for (int r2 = 0; r2 < nRow; ++r2)
            for (int c2 = 0; c2 < nCol; ++c2) {
              int d1 = dist[r][c][rk][ck];
              int d2 = dist[rk][ck][r2][c2];
              if (d1 != 2E9L && d2 != 2E9L) {
                dist[r][c][r2][c2] = min(dist[r][c][r2][c2], d1 + d2);
              }
            }
  long long maxTime = -2E18L;
  for (int r = 0; r < nRow; ++r)
    for (int c = 0; c < nCol; ++c) {
      for (int m = 0; m < nMale; ++m) {
        best[0][m][r][c] = 2E18L;
        int dMale = dist[r][c][row[0][m]][col[0][m]];
        if (dMale != 2E9L) {
          long long timeMale = (long long)dMale * speed[0][m];
          best[0][m][r][c] = timeMale;
          maxTime = max(maxTime, timeMale);
        }
      }
      for (int f = 0; f < nFemale; ++f) {
        best[1][f][r][c] = 2E18L;
        int dFemale = dist[r][c][row[1][f]][col[1][f]];
        if (dFemale != 2E9L) {
          long long timeFemale = (long long)dFemale * speed[1][f];
          best[1][f][r][c] = timeFemale;
          maxTime = max(maxTime, timeFemale);
        }
      }
    }
  for (int r = 0; r < nRow; ++r)
    for (int c = 0; c < nCol; ++c) {
      if (board[r][c] == '.') {
        squareID[r][c] = nSquare;
        nSquare++;
      }
    }
  long long left = 0, right = maxTime, mid, ret = -1;
  while (left <= right) {
    mid = (left + right) / 2;
    int nNode = nMale + nFemale + 2 * nSquare + 2;
    Network g(nNode);
    int source = nNode - 2;
    int sink = nNode - 1;
    for (int m = 0; m < nMale; ++m) {
      g.addEdge(source, m, 1);
    }
    for (int f = 0; f < nFemale; ++f) {
      g.addEdge((nMale + f), sink, 1);
    }
    for (int x = 0; x < nSquare; ++x) {
      g.addEdge((nMale + nFemale + x), (nMale + nFemale + nSquare + x), 1);
    }
    for (int m = 0; m < nMale; ++m)
      for (int r = 0; r < nRow; ++r)
        for (int c = 0; c < nCol; ++c) {
          if (best[0][m][r][c] != 2E18L && best[0][m][r][c] <= mid) {
            g.addEdge(m, (nMale + nFemale + squareID[r][c]), 1);
          }
        }
    for (int f = 0; f < nFemale; ++f)
      for (int r = 0; r < nRow; ++r)
        for (int c = 0; c < nCol; ++c) {
          if (best[1][f][r][c] != 2E18L && best[1][f][r][c] <= mid) {
            g.addEdge((nMale + nFemale + nSquare + squareID[r][c]), (nMale + f),
                      1);
          }
        }
    int bestMatch = Dinic(g, source, sink).run();
    if (bestMatch == nMale) {
      ret = mid;
      right = mid - 1;
    } else {
      left = mid + 1;
    }
  }
  cout << ret << endl;
  return 0;
}
