只要能看出来是二分图的最优匹配,然后建图,套模板,应该就能过了,几乎是裸模板题,听 亚伟 说去年现场赛的时候小伟他们1Y过掉这个题,然后就尝试了下,的确不是很难,这又给了我们弱小心灵一点点希望和安慰……
我用的是 KM算法 ,调整顶标值加上一直 dfs 找增广路(就是二分图最大匹配的匈牙利算法),具体解释参见:
http://hi.baidu.com/wwbmmm/blog/item/7f356cfa92d23962034f56e5.html
PS:不要光看博文,下面有个牛牛的评论,相当给力!!!
我的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<climits>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
const int N = 30;
struct point{
char name;
int id;
};
point pa[N],pb[N];
int map[N][N],len,g,stu;
void addpoint_a(char x,int &k1){//构造二分图的x点集
int i,add=1;
for(i=1;i<k1;i++){
if(x==pa[i].name){
add=0;break;
}
}
if(add){
pa[k1].name=x;
pa[k1].id=k1;
k1++;
}
}
void addpoint_b(char x,int &k2){//构造二分图的y点集
int i,add=1;
for(i=1;i<k2;i++){
if(x==pb[i].name){
add=0;break;
}
}
if(add){
pb[k2].name=x;
pb[k2].id=k2;
k2++;
}
}
int searchx(char x,point p[]){
for(int i=1;i<=g;i++){
if(p[i].name==x)return p[i].id;
}
return -1;
}
int lx[N],ly[N],match[N],visx[N],visy[N],lack;
int dfs(int x){//匈牙利
visx[x]=1;
for(int i=1;i<=g;i++){
if(!visy[i] && lx[x]+ly[i]==map[x][i]){
visy[i]=1;
if(match[i]==-1 || dfs(match[i])){
match[i]=x;
return 1;
}
}
}
return 0;
}
int KM(){
int i,j,k;
for(i=1;i<=g;i++){//初始化顶标
lx[i]=INT_MIN; ly[i]=0;
for(j=1;j<=g;j++)
lx[i]=max(map[i][j],lx[i]);
}
memset(match,-1,sizeof(match));
for(i=1;i<=g;i++){
while(1){//直到每个点都成功匹配,才结束循环
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(i))break; //如果点 i 成功匹配,则不需要调整定标值
/*------------顶标调整------------*/
int lack=INT_MAX;//顶标调整值
for(j=1;j<=g;j++){
if(visx[j]){
for(k=1;k<=g;k++){//取幅度最小的值为调整值
if(!visy[k])lack=min(lx[j]+ly[k]-map[j][k],lack);
}
}
}
for(j=1;j<=g;j++){//调整已经得到匹配的点对的顶标值
if(visx[j])lx[j]-=lack;
if(visy[j])ly[j]+=lack;
}
/*---------------------------------*/
}
}
int sum=0;
for(i=1;i<=g;i++){
if(match[i]!=-1)sum+=map[match[i]][i];
}
return sum;
}
void solve()
{
int i,j;
char str[10010],ch[3];
scanf("%d%d%d",&len,&g,&stu);
int k1=1;
for(i=1;i<=len;i++){
scanf("%s",ch);
str[i]=ch[0];
addpoint_a(str[i],k1);
}
for(i=0;i<stu;i++){
int k2=1;
memset(map,0,sizeof(map));
memset(pb,0,sizeof(pb));
for(j=1;j<=len;j++){
scanf("%s",ch);
addpoint_b(ch[0],k2);
int a=searchx(str[j],pa);
int b=searchx(ch[0],pb);
map[a][b]++;
}
int ans=KM();
printf("%.4lf\n",ans*1.0/len);
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
solve();
}
return 0;
}