题意:两串字母匹配,求最大权匹配除以长度。
二分图最大权匹配KM算法模板题。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 'Z' + 10;
const int INF = 0x3f3f3f3f;
//接口:KM()
//输入:w[][] 全局变量,表示带权图
// pop 全局变量,表示图一侧的点数
//输出:最大权匹配的值
// son_y[] 全局变量,表示匹配方案
int T;
int n, m, k;
char s[10010];
char ss[10010];
int w[maxn][maxn], x[maxn], y[maxn];
int prev_x[maxn], prev_y[maxn], son_y[maxn], slack[maxn], par[maxn];
int lx, ly, pop;
void init()
{
memset(w, 0, sizeof(w));
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
memset(prev_x, 0, sizeof(prev_x));
memset(prev_y, 0, sizeof(prev_y));
memset(son_y, 0, sizeof(son_y));
memset(slack, 0, sizeof(slack));
memset(par, 0, sizeof(par));
}
void adjust(int v)
{
son_y[v] = prev_y[v];
if (prev_x[son_y[v]] != -2)
adjust(prev_x[son_y[v]]);
}
bool find(int v)
{
for (int i = 0; i < pop; i++)
{
if (prev_y[i] == -1)
{
if (slack[i] > x[v] + y[i] - w[v][i])
{
slack[i] = x[v] + y[i] - w[v][i];
par[i] = v;
}
if (x[v] + y[i] == w[v][i])
{
prev_y[i] = v;
if (son_y[i] == -1)
{
adjust(i);
return true;
}
if (prev_x[son_y[i]] != -1) continue;
prev_x[son_y[i]] = i;
if (find(son_y[i])) return true;
}
}
}
return false;
}
int KM()//接口
{
int i, j, m;
for (i = 0; i < pop; i++)
{
son_y[i] = -1;
y[i] = 0;
}
for (i = 0; i < pop; i++)
{
x[i] = 0;
for (j = 0; j < pop; j++)
x[i] = max(x[i], w[i][j]);
}
bool flag;
for (i = 0; i < pop; i++) {
for (j = 0; j < pop; j++)
{
prev_x[j] = prev_y[j] = -1;
slack[j] = INF;
}
prev_x[i] = -2;
if (find(i)) continue;
flag = false;
while (!flag)
{
m = INF;
for (j = 0; j < pop; j++)
if (prev_y[j] == -1)
m = min(m, slack[j]);
for (j = 0; j < pop; j++)
{
if (prev_x[j] != -1) x[j] -= m;
if (prev_y[j] != -1) y[j] += m;
else slack[j] -= m;
}
for (j = 0; j < pop; j++)
{
if (prev_y[j] == -1 && !slack[j])
{
prev_y[j] = par[j];
if (son_y[j] == -1)
{
adjust(j);
flag = true;
break;
}
prev_x[son_y[j]] = j;
if (find(son_y[j]))
{
flag = true;
break;
}
}
}
}
}
int ans = 0;
for (int i = 0; i < pop; i++)
ans += w[son_y[i]][i];
return ans;
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d %d %d", &n, &m, &k);
for (int i = 0; i < n; i++)
scanf(" %c", &s[i]);
while (k--)
{
for (int i = 0; i < n; i++)
scanf(" %c", &ss[i]);
init();
for (int i = 0; i < n; i++)
w[s[i] - 'A'][ss[i] - 'A']++;
pop = 26;
double ans = (double)KM() / (double)n;
printf("%.4f\n",ans);
}
}
}