把对应位置的字母边练起来,权值加一,最后求二分图最大权值即可。
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=30+5;
int w[maxn][maxn],n,m;
int lx[maxn],ly[maxn];
int Left[maxn];
bool s[maxn],t[maxn];
char ss[35][20005];
char tt[20005];
bool match(int i)
{
s[i]=true;
for(int j=1;j<=m;j++) if(lx[i]+ly[j]==w[i][j]&&!t[j]){
t[j]=true;
if(Left[j]==-1||match(Left[j])){
Left[j]=i;
return true;
}
}
return false;
}
void update()
{
int a=(1<<30);
for(int i=1;i<=n;i++) if(s[i])
for(int j=1;j<=m;j++) if(!t[j])
a=min(a,lx[i]+ly[j]-w[i][j]);
for(int i=1;i<=n;i++) if(s[i]) lx[i]-=a;
for(int i=1;i<=m;i++) if(t[i]) ly[i]+=a;
}
void KM()
{
memset(Left,-1,sizeof(Left));
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
lx[i]=max(lx[i],w[i][j]);
}
for(int i=1;i<=n;i++){
for(;;)
{
memset(s,0,sizeof(s));
memset(t,0,sizeof(t));
if(match(i)) break;else update();
}
}
}
int r,k,c;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&r,&k,&c);
n=m=26;
getchar();gets(tt);
for(int i=0;i<c;i++) gets(ss[i]);
for(int i=0;i<c;i++)
{
memset(w,0,sizeof(w));
for(int j=0;j<=2*(r-1);j+=2) {
w[ss[i][j]-'A'+1][tt[j]-'A'+1]++;
}
KM();
int ans=0;
for(int i=1;i<=26;i++) ans+=w[Left[i]][i];
printf("%.4f\n",(double)ans/r);
}
}
return 0;
}