zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    拷贝构造函数的用法
    虚基类的用法
    函数模板的用法,以及类外定义的注意事项
    怎么学好python?
    树状数组单点更新和区间查询
    线段树的基本操作
    快排算法的实现
    react-redux 中 connect 的常用写法
    ant-design表单处理和常用方法及自定义验证
    ionic 签名、打包
  • 原文地址:https://www.cnblogs.com/takeoffyoung/p/4933961.html
Copyright © 2011-2022 走看看