建图过程,上面一行字母与下面一行一一对应连边,再利用KM求一个最优匹配即可
#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<stdlib.h>
using namespace std;
#define MIN(a,b) a<b?a:b
#define INF 999999
#define MAX 50
int match[MAX];
bool sx[MAX],sy[MAX];
int lx[MAX],ly[MAX],map[MAX][MAX];
bool path(int u)
{
sx[u]=true;
for(int v=0;v<26;v++)
if(!sy[v]&&lx[u]+ly[v]==map[u][v])
{
sy[v]=true;
if(match[v]==-1||path(match[v]))
{
match[v]=u;
return true;
}
}
return false;
}
int KM(int n)
{
int i,j;
for(i=0;i<n;i++)
{
lx[i]=-INF;
ly[i]=0;
for(j=0;j<n;j++)
if(lx[i]<map[i][j])
lx[i]=map[i][j];
}
memset(match,-1,sizeof(match));
for(int u=0;u<n;u++)
while(1)
{
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
if(path(u)) break;
int dmin=INF;
for(i=0;i<n;i++)
if(sx[i])
for(j=0;j<n;j++)
if(!sy[j])
dmin=MIN(lx[i]+ly[j]-map[i][j],dmin);
for(i=0;i<n;i++)
{
if(sx[i])
lx[i]-=dmin;
if(sy[i])
ly[i]+=dmin;
}
}
int sum=0;
for(j=0;j<n;j++)
sum+=map[match[j]][j];
return sum;
}
void init(int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(!map[i][j])
map[i][j]=INF;
}
}
char s[10010],tmp[10010];
double ans[35];
int main()
{
int i,j;
int t,n,k,m;
char str[5];
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&k,&m);
for(i=0;i<n;i++)
{
scanf("%1s",str);
s[i]=str[0];
}
s[i]='\0';//printf("%s\n",s);
for(i=0;i<m;i++)
{
memset(map,0,sizeof(map));
for(j=0;j<n;j++)
{
scanf("%1s",str);
tmp[j]=str[0];
}
tmp[j]='\0';
for(j=0;j<n;j++)
map[s[j]-'A'][tmp[j]-'A']++;
//init(30);
int res=KM(26);
ans[i]=1.0*res/n;
}
for(i=0;i<m;i++)
printf("%.4lf\n",ans[i]);
}
return 0;
}