传送门
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b, ll p)
{
ll res = 1;
while(b)
{
if(b & 1)res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
const int inf = 0x3f3f3f3f;
#define PI acos(-1)
const int maxn=100000 + 5;///总点个数,随题意改
const int MAX=1<<26;///最大值,随题意改
///链式前向星存储边
///表示u->v 边权为c(容量) 下一条边
struct Edge{
ll u,v,c,ne;
};
///求最大流
struct Dinic{
int n,m;///点数,边数
int edn;///建图时所用边数
int p[maxn];///链式前向星存图的父节点
int d[maxn];///分层建图时表示的层数
int sp,tp;///原点 汇点
Edge edge[maxn*6];///存储边
///初始化
void init(){
///this->sp=sp;//可省去
/// this->tp=tp;
edn=0;///清空建图时计边的计数器
memset(p,-1,sizeof p);
/// memset(p,-1,sizeof(int)*(n+2));///小优化 仅初始化使用的空间
}
void addedge(int u,int v,int c){///建图加边
edge[edn]={u,v,c,p[u]};p[u]=edn++;///正向一定要加的
edge[edn]={v,u,0,p[v]};p[v]=edn++;///无向图改成c 反悔边
}
///分层建图并且寻找增广路的过程
int bfs(){
queue<int>q;
while(!q.empty()) q.pop();///清空队列
memset(d,-1,sizeof d);///初始化距离数组
d[sp]=0;q.push(sp);///进行分层建图
while(!q.empty()){
int cur=q.front();q.pop();
for(int i=p[cur];~i;i=edge[i].ne){
int u=edge[i].v;
if(d[u]==-1&&edge[i].c>0){///容量>0才会有贡献
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp]!=-1;///是否存在增广路
}
ll dfs(ll a,ll b){
ll r=0;
if(a==tp) return b;///到达汇点
for(int i=p[a];~i&&r<b;i=edge[i].ne){
int u=edge[i].v;
if(edge[i].c>0&&d[u]==d[a]+1){
///只拓展下一层 并且容量>0才会有贡献
int x=min(edge[i].c,b-r);///可以增加的流量
x=dfs(u,x);
r+=x;///统计流量
///更新边权:找到反向边
///奇数异或1相当于-1,偶数异或1相当于+1
edge[i].c-=x;///回溯时更新
edge[i^1].c+=x;///成对变换
}
///if(!r) break;
}
if(!r) d[a]-=2;///uncertain
return r;
}
ll Maxflow(){
ll total=0,t;
while(bfs()){
while(t=dfs(sp,MAX)) total+=t;///增广找到流量
}
return total;
}
}dinic;
map<string,int>s1,s2;///插头和插座
int main()
{
int T=read;
while(T--){
dinic.n=read;
dinic.init();
s1.clear(),s2.clear();
int tot=0,num=0;
dinic.sp=80001,dinic.tp=dinic.sp+1;
for(int i=1;i<=dinic.n;i++){
string s;cin>>s;
s1[s]=++tot;
}
ll m=read;
for(int i=1;i<=m;i++){
string x,y;cin>>x>>y;
s2[x]=++num;
if(s1.find(y)==s1.end()) s1[y]=++tot;
dinic.addedge(s2[x],m+s1[y],1);
dinic.addedge(dinic.sp,s2[x],1);
}
int k=read;
for(int i=1;i<=dinic.n;i++){
dinic.addedge(m+i,m+tot+i,1);
dinic.addedge(m+tot+i,dinic.tp,1);
}
for(int i=1;i<=k;i++){
string x,y;cin>>x>>y;
dinic.addedge(s1[x]+m,s1[y]+m,inf);
}
printf("%lld\n",m-dinic.Maxflow());
if(T) puts("");
}
return 0;
}