hdu3718(二分图最大权匹配,模板题)

题意:

  给定模板序列,和m个代考察序列,求出每个序列和模板序列的相似度。

  其中相似度的定义:待考察序列中的相同字母,均可以替换成其他相同字母。例如 A B A A C 可以替换成 B B B B C 或者 C B C C C。或者A A A A A(B C都变成A)。替换完成后,对应位置字母相同的数量 ,除以序列长度即为答案。

解决:

  每个待考察序列建图,扫一遍序列,图ma[26][26]对应字母替换之后的收益。即为二分图。跑一下KM。

#include <bits/stdc++.h>

const int MAXN = 40;
const int INF = 0x3f3f3f3f;

int n, nx, ny;
int lx[MAXN], ly[MAXN];
int ma[MAXN][MAXN];
int slack[MAXN], match[MAXN];
bool visx[MAXN], visy[MAXN];

bool findPath(int x)
{
    visx[x] = true;
     for (int y = 1; y <= ny; ++y) {
        if (true == visy[y]) {
            continue;
        }
        int tmp = lx[x] +ly[y] - ma[x][y];
        if (0 == tmp) {
            visy[y] = true;
            if (-1 == match[y] || true == findPath(match[y])) {
                match[y] = x;
                return true;
            }
        }
        if (slack[y] > tmp)
            slack[y] = tmp;
     }
     return false;
}

int km()
{
    nx = ny = n;
    memset(match, -1, sizeof match);
    memset(ly, 0, sizeof ly);
    for (int x = 1; x <= nx; ++x) {
        lx[x] = -INF;
        for (int y = 1; y <= ny; ++y) {
            lx[x] = std::max(lx[x], ma[x][y]);
        }
    }
    for (int x = 1; x <= nx; ++x) {
        for (int y = 1; y <= ny; ++y) {
            slack[y] = INF;
        }
        while (true) {
            memset(visx, false, sizeof visx);
            memset(visy, false, sizeof visy);
            if (true == findPath(x))
                break;
            int min_d = INF;
            for (int y = 1; y <= ny; ++y) {
                if (false == visy[y] && min_d > slack[y]) {
                    min_d = slack[y];
                }
            }
            for (int x = 1; x <= nx; ++ x) {
                if (true == visx[x]) {
                    lx[x] -= min_d;
                }
            }
            for (int y = 1; y <= ny; ++y) {
                if (true == visy[y]) {
                    ly[y] += min_d;
                }
                else
                    slack[y] -= min_d;
            }
        }
    }
    int res = 0;
    for (int y = 1; y <= ny; ++y) {
        if (-1 != match[y]) {
            res += ma[match[y]][y];
        }
    }
    return res;
}

char pat[10000+10];
char buf[10000+10];

int main()
{
    int T;
    scanf("%d", &T);
    while (T--) {
        int l, tmp, m;
        scanf("%d%d%d", &l, &tmp, &m);
        n = 26;
        char cmd[4];
        for (int i = 1; i <= l; ++i) {
            scanf("%s", cmd);
            pat[i] = cmd[0];
        }
        while (m -- ){
            memset(ma, 0, sizeof ma);
            for (int i = 1; i <= l; ++i) {
                scanf("%s", cmd);
                buf[i] = cmd[0];
                ma[pat[i] - 'A' + 1][buf[i] - 'A' + 1]++;
            }
            int res = km();
//            printf("res = %d
", res);
            printf("%.4f
", 1.0*res/l);
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/takeoffyoung/p/4933961.html