只要能看出来是二分图的最优匹配,然后建图,套模板,应该就能过了,几乎是裸模板题,听 亚伟 说去年现场赛的时候小伟他们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; }