#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
#include<unordered_map>
#define all(a) (a).begin(), (a).end()
using namespace std;

typedef vector< vector<int> > Graph;

class HashFunc{
  public:
    size_t operator()(const vector<int> &v) const {
      size_t k = 1111, val = 0;
      for(int x : v) val = val * k + x;
      return val;
    }
};

Graph readGraph(int n, int m){
  Graph g(n);
  while(m--){
    int a,b;
    scanf("%d%d",&a, &b); a--; b--;
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  return g;
}

vector<Graph> connectedComponentDecomp(Graph g){
  int n = g.size();
  vector<int> id(n, -1);

  vector<Graph> f;
  for(int v=0;v<n;v++){
    if(id[v]>=0) continue;
    Graph t(1);

    int size = 0;
    id[v] = size++;
    stack<int> q;
    q.emplace(v);

    while(q.size()){
      int u = q.top(); q.pop();
      for(int w : g[u]){
        if(id[w]>=0) continue;
        id[w] = size++;
        q.emplace(w);

        t.emplace_back( vector<int>() );
        t[id[u]].emplace_back(id[w]);
        t[id[w]].emplace_back(id[u]);
      }
    }

    f.emplace_back(t);
  }
  return f;
}

void dfs(int v, vector<int> &dis, const Graph &g){
  stack<int> q;
  q.emplace(v);
  dis[v] = 0;

  while(not q.empty()){
    v = q.top(); q.pop();
    for(int u : g[v]) {
      if(dis[u]>=0) continue;
      dis[u] = dis[v]+1;
      q.emplace(u);
    }
  }
}

vector<int> getCenters(const Graph &t){
  int n = t.size();
  vector<int> d0(n,-1), da(n, -1), db(n, -1);
  dfs(0, d0, t);
  int a = distance(d0.begin(), max_element(all(d0)));

  dfs(a, da, t);
  int b = distance(da.begin(), max_element(all(da)));

  dfs(b, db, t);

  int dia = da[b];
  vector<int> centers;
  for(int v=0; v<n; v++){
    if(da[v] + db[v] == dia and (da[v] == dia/2 or db[v] == dia/2)){
      centers.emplace_back(v);
    }
  }
  return centers;
}

int calcHash(int r, const Graph &t, unordered_map< vector<int>, int, HashFunc > &hash){
  int n = t.size();
  vector< vector<int> > child_hashes(n);
  vector<int> p(n,-1);
  stack<int> s;
  s.emplace(r+1); s.emplace(-r-1);

  while(not s.empty()) {
    int x = s.top(); s.pop();
    if(x<0){
      int v = -x-1;
      for(int u : t[v]){
        if(p[v] == u) continue;
        p[u] = v;
        s.emplace(u+1); s.emplace(-u-1);
      }
    }else{
      int v = x-1;
      sort(all(child_hashes[v]));
      if( hash.count(child_hashes[v]) == 0 ){
        hash[child_hashes[v]] = hash.size();
      }

      if(p[v]>=0) child_hashes[p[v]].emplace_back(hash[child_hashes[v]]);
    }
  }

  return hash[child_hashes[r]];
}

bool isRootedIsomorphic(int r1, const Graph &t1, int r2, const Graph &t2){
  unordered_map< vector<int>, int, HashFunc > hash;

  return calcHash(r1, t1, hash) == calcHash(r2, t2, hash);
}

int main(){
  int nf, mf;
  scanf("%d%d",&nf, &mf);
  vector<Graph> f = connectedComponentDecomp( readGraph(nf, mf) );

  int nt;
  scanf("%d",&nt);
  Graph t = readGraph(nt, nt-1);
  vector<int> t_centers = getCenters(t);
  int r1 = t_centers[0];

  int ans = 0;
  for(Graph& st : f) {
    if(st.size() != t.size()) continue;

    vector<int> st_centers = getCenters(st);
    if(t_centers.size() != st_centers.size()) continue;

    for(int r2 : st_centers) {
      if( isRootedIsomorphic(r1, t, r2, st) ){
        ans++; break;
      }
    }
  }

  cout << ans << endl;
}


Measured memory_bytes: 55592