解题思路:二分图。
建图:将学生的答案所映射的正确答案作为二分图的边,边权值为1,有两条就为2,依此类推。
然后用KM算法求出最佳匹配。除以n 就是要求的答案了。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; #define N 101 #define MIN -0xfffffff #define MAX 0xfffffff #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(a) ((a)>0?(a):-(a)) const int alph = 26; int map[N][N]; int l[N],r[N], ln[N],rn[N]; int link[N]; void init(){ memset(link,-1,sizeof(link)); memset(rn,0,sizeof(rn)); for(int i = 0; i < alph; i++){ ln[i] = MIN; for(int j = 0; j < alph; j++){ ln[i] = max(ln[i],map[i][j]); } } } int dfs(int k) { l[k] = 1; for(int i = 0; i < alph; i++) { if(!r[i]&&ln[k] + rn[i] == map[k][i]) { r[i] = 1; if(link[i] == -1 || dfs(link[i])) { link[i] = k; return 1; } } } return 0; } void adjust(){ int minm = MAX; for(int i = 0; i < alph; i ++){ if(l[i]){ for(int j = 0; j < alph; j++){ if(!r[j]){ minm = min(minm,ln[i]+rn[j]-map[i][j]); } } } } for(int i = 0; i < alph; i++){ if(l[i]){ ln[i] -= minm; } if(r[i]){ rn[i] += minm; } } } int main() { int n, m, k; int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&k,&m); char ans[10001], s[11]; for(int i = 0; i < n; i++){ scanf("%s",s); ans[i] = s[0]; } while(m--){ memset(map,0,sizeof(map)); for(int i = 0; i < n; i++){ scanf("%s",s); map[ans[i] - 'A'][s[0]-'A']++; } init(); for(int i = 0; i < alph; i++){ while(1){ memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); if(dfs(i))break; else adjust(); } } int sum = 0; for(int i = 0; i < alph; i++){ sum += map[link[i]][i]; } printf("%.4f\n",sum/(double)n); } } return 0; }