#include <bits/stdc++.h>
using namespace std;
const long double EPS = 1e-9;
const long double PI = acos(-1.0);
const int MX = 6e5 + 5;
long long mod = 1e9 + 7;
int n;
bool edges[15][15];
vector<int> Givenadj[15];
int lca[15][15], mustBeIn[15], cantBeIn[15];
unordered_map<int, int> memp[1 << 14];
int pokpok[1 << 13];
bool okay(int m) {
  if (~pokpok[m]) return pokpok[m];
  for (int i = 0; i < n; i++) {
    if ((m >> i) & 1) {
      for (int j = i + 1; j < n; j++) {
        if ((m >> j) & 1) {
          if (lca[i][j] == -1)
            ;
          else if ((m >> lca[i][j]) & 1)
            ;
          else
            return pokpok[m] = 0;
        }
      }
    }
  }
  return pokpok[m] = 1;
}
int partitioning(int m1, int m2, int p) {
  if (m1 > m2) swap(m1, m2);
  if (m1 == 0) return 1;
  if (((memp[m1]).find(m2) != (memp[m1]).end()))
    return memp[m1][m2] == p or memp[m1][m2] == -1;
  int curp = -1;
  for (int i = 0; i < n; i++) {
    if ((m1 >> i) & 1) {
      for (int j = 0; j < n; j++) {
        if ((m2 >> j) & 1) {
          if (~lca[i][j]) {
            if (curp == -1)
              curp = lca[i][j];
            else if (curp == lca[i][j])
              ;
            else {
              memp[m1][m2] = -2;
              return 0;
            }
          }
        }
      }
    }
  }
  memp[m1][m2] = curp;
  return (curp == p or curp == -1);
}
long long mem[14][1 << 14];
int A[13], B[13], M;
long long dp(int p, int msk) {
  if (!(msk & (msk - 1))) return 1;
  if (!msk) return 1;
  long long &res = mem[p][msk];
  if (~res) return res;
  res = 0;
  int MustSibling = 0;
  vector<int> sibs;
  for (int i = 0; i < n; i++) {
    if ((msk >> i) & 1 and edges[p][i])
      MustSibling |= (1 << i), sibs.push_back(i);
  }
  int remains = msk;
  int done1 = -1, done2 = -1;
  for (int m = remains; m; m = (m - 1) & remains) {
    for (int u = 0; u < n; u++) {
      if ((m >> u) & 1) {
        assert((msk | m) == msk);
        int current_tree = m;
        int remaining_tree = (msk ^ m);
        if ((current_tree | mustBeIn[u]) != current_tree) continue;
        if (cantBeIn[u] & current_tree) continue;
        if (done1 == -1 or ((current_tree >> done1) & 1))
          ;
        else
          continue;
        if (!okay(current_tree)) continue;
        if (!okay(remaining_tree | (1 << p))) continue;
        bool valid = 1;
        for (int k = 0; k < M; k++) {
          if (A[k] == u) {
            valid &= ((B[k] == p) | ((current_tree >> B[k]) & 1));
          } else if ((current_tree >> A[k]) & 1) {
            valid &= (((current_tree >> B[k]) & 1));
          }
          if (B[k] == u) {
            valid &= ((A[k] == p) | ((current_tree >> A[k]) & 1));
          } else if ((current_tree >> B[k]) & 1) {
            valid &= (((current_tree >> A[k]) & 1));
          }
          if ((remaining_tree >> A[k]) & 1) {
            valid &= ((B[k] == p) | ((remaining_tree >> B[k]) & 1));
          }
          if ((remaining_tree >> B[k]) & 1) {
            valid &= ((A[k] == p) | ((remaining_tree >> A[k]) & 1));
          }
        }
        if (!valid) continue;
        if (partitioning(current_tree, remaining_tree, p) == 0) continue;
        res += dp(u, current_tree ^ (1 << u)) * dp(p, remaining_tree);
        if (done1 == -1)
          for (int k = n - 1; k >= 0; k--)
            if (((current_tree >> k) & 1)) {
              done1 = k;
              break;
            }
      }
    }
  }
  return res;
}
int main() {
  int m, q, u, v, c;
  cin >> n >> m >> q;
  M = m;
  for (int i = 0; i < m; i++) {
    cin >> u >> v;
    u--, v--;
    A[i] = u, B[i] = v;
    edges[u][v] = edges[v][u] = 1;
    Givenadj[u].push_back(v);
    Givenadj[v].push_back(u);
  }
  memset(lca, -1, sizeof(lca));
  for (int i = q; i--;) {
    cin >> u >> v >> c;
    u--, v--, c--;
    if (lca[u][v] == -1 or lca[u][v] == c)
      ;
    else {
      cout << 0 << '\n';
      return 0;
    }
    if (v == u and c != v) {
      cout << 0 << '\n';
      return 0;
    }
    if ((u == 0 or v == 0) and c != 0) {
      cout << 0 << '\n';
      return 0;
    }
    lca[v][u] = lca[u][v] = c;
    if (u == v and v == c)
      ;
    else if (u == v)
      mustBeIn[c] |= (1 << u), cantBeIn[u] |= (1 << c);
    else if (u == c)
      mustBeIn[c] |= (1 << v), cantBeIn[v] |= (1 << c);
    else if (v == c)
      mustBeIn[c] |= (1 << u), cantBeIn[u] |= (1 << c);
    else {
      mustBeIn[c] |= (1 << u), cantBeIn[u] |= (1 << c);
      mustBeIn[c] |= (1 << v), cantBeIn[v] |= (1 << c);
    }
  }
  for (int i = 0; i < n; i++) mustBeIn[i] |= (1 << i);
  while (1) {
    bool chaged = 0;
    for (int i = 0; i < n; i++) {
      if (mustBeIn[i] ^ (1 << i))
        for (int j = 0; j < n; j++) {
          if ((mustBeIn[i] >> j) & 1) {
            if ((mustBeIn[i] | mustBeIn[j]) == mustBeIn[i])
              ;
            else
              mustBeIn[i] |= mustBeIn[j], chaged = 1;
          }
        }
    }
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        if (i != j and ((mustBeIn[i] >> j) & 1) and ((mustBeIn[j] >> i) & 1)) {
          cout << 0 << '\n';
          return 0;
        }
        if ((i != j and (mustBeIn[i] >> j) & 1) and ((cantBeIn[i] >> j) & 1)) {
          cout << 0 << '\n';
          return 0;
        }
      }
    }
    if (not chaged) break;
  }
  memset(pokpok, -1, sizeof(pokpok));
  memset(mem, -1, sizeof(mem));
  cout << dp(0, (1 << n) - 2) << '\n';
  return 0;
}
