/* 二分图 最大权匹配问题,题目给定条件可以看出是完备匹配; 利用最小费用最大流解决 X集合连源点,边权为1,花费0 Y集合连汇点,边权为1,花费0 X连Y中任意元素,边权为1,花费为权值的相反数 最后得到的最小费用就是最大权匹配 */ #include <stdio.h> #include <iostream> #include <string.h> #include<queue> #include<cmath> using namespace std; const int M=20010,ME=500000; const int INF=0x3f3fffff; //****************************** int Head[M],Next[ME],Num[ME],Flow[ME],Cap[ME],Cost[ME],Q[M],InQ[M],Len[M],pre_edge[M]; class MaxFlow { public: void clear() { memset(Head,-1,sizeof(Head)); memset(Flow,0,sizeof(Flow)); } void addedge(int u,int v,int cap,int cost) { Next[top] = Head[u]; Num[top] = v; Cap[top] = cap; Cost[top] = cost; Head[u] = top++; Next[top] = Head[v]; Num[top] = u; Cap[top] = 0; Cost[top] = -cost; Head[v] = top++; } int solve(int s,int t) //返回最终的cost { int cost = 0; while(SPFA(s,t)) { int cur = t,minflow = INF; while(cur != s) { if(minflow > Cap[pre_edge[cur]]-Flow[pre_edge[cur]]) minflow = Cap[pre_edge[cur]]-Flow[pre_edge[cur]]; cur = Num[pre_edge[cur] ^ 1]; } cur = t ; while(cur != s) { Flow[pre_edge[cur]] += minflow; Flow[pre_edge[cur] ^ 1] -= minflow; cost += minflow * Cost[pre_edge[cur]]; cur = Num[pre_edge[cur] ^ 1]; } } return cost; } private: bool SPFA(int s,int t) { fill(Len,Len+M,INF); Len[s]=0; int head = -1,tail = -1,cur; Q[++head] = s; while(head != tail) { ++tail; if(tail >= M) tail = 0 ; cur = Q[tail]; for(int i = Head[cur];i != -1;i = Next[i]) { if(Cap[i]>Flow[i] && Len[Num[i]] > Len[cur] + Cost[i]) { Len[Num[i]] = Len[cur] + Cost[i]; pre_edge[Num[i]] = i; if(!InQ[Num[i]]) { InQ[Num[i]]=true; ++head; if(head >= M) head = 0; Q[head] = Num[i]; } } } InQ[cur]=false; } return Len[t] != INF; } int top; }my; //****************************** int n,m,k; char ans[10009][2]; char mo[10009][2]; int flow[40][40]; int main() { int ca; scanf("%d",&ca); while(ca--) { scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) { scanf("%s",ans[i]); } while(k--) { my.clear(); memset(flow,0,sizeof(flow)); for(int i=0;i<n;i++) { scanf("%s",mo[i]); flow[ans[i][0]-'A'+1][mo[i][0]-'A'+1]++; } for(int i=1;i<=26;i++) { for(int j=1;j<=26;j++) my.addedge(i,j+26,1,-flow[i][j]); my.addedge(0,i,1,0); my.addedge(i+26,53,1,0); } printf("%.4lf\n",-my.solve(0,53)*1.0/(1.0*n)); } } return 0; }