zoukankan      html  css  js  c++  java
  • HDU3718 Similarity 最大权值匹配

    题意:给定一个进行了集合划分的序列,现有一套标准答案,同样给定了M个非标准答案,现在要计算这M个非标准答案的最大正确率为多少?

    解法:该题考虑的是可以采用不同的字符进行相同的划分。那么求解的就是一个集合符号的匹配的问题,采用何种的集合符号一一对应才能使得正确率最高。那么对于每对应某个位置的集合标号,我们可以假设是对应的,那么在这个基础上再进行更多的匹配,建立起x字符对应y字符最多能够对多少个的一个边,然后调用KM算法即可。在读取数据的时候使用gechar死活过不了(会读到非字母导致RE,可能是数据中有多个空格或者...),还好有cin这个利器,不过就是速度慢了点。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    int N, M, K;
    int w[30][30];
    int lx[30], ly[30];
    int sx[30], sy[30];
    int match[30], slack[30];
    char ans[10005];
    char tmp[10005];
    vector<int>v[30];
    
    void build() { // 构图
        memset(w, 0, sizeof (w));
        int cnt, lch, rch;
        for (int i = 1; i <= N; ++i) {
            cnt = 0;
            lch = tmp[i]-'A', rch = ans[i]-'A';if (!w[lch][rch]) {
                for (int j = 0; j < v[rch].size(); ++j) {
                    if (tmp[v[rch][j]] == tmp[i]) {
                        ++cnt;
                    }
                }
                w[lch][rch] = cnt;
            }
        }
    }
    
    int path(int u) {
        sx[u] = 1;
        for (int i = 0; i < 26; ++i) {
            if (sy[i]) continue;
            int t = lx[u] + ly[i] - w[u][i];
            if (!t) {
                sy[i] = 1;
                if (match[i] == -1 || path(match[i])) {
                    match[i] = u;
                    return true;
                }    
            } else {
                slack[i] = min(slack[i], t);
            }
        }
        return false;
    }
    
    void KM() {
        memset(match, 0xff, sizeof (match)); // 由于0号元素同样是有效编号,初始化为-1
        memset(lx, 0, sizeof (lx));
        memset(ly, 0, sizeof (ly));
        for (int i = 0; i < 26; ++i) {
            for (int j = 0; j < 26; ++j) {
                lx[i] = max(lx[i], w[i][j]);    
            }
        }
        for (int i = 0; i < 26; ++i) {
            memset(slack, 0x3f, sizeof (slack));
            while (1) {
                memset(sx, 0, sizeof (sx));
                memset(sy, 0, sizeof (sy));
                if (path(i)) break;
                int d = 0x3f3f3f3f;
                for (int j = 0; j < 26; ++j) {
                    if (!sy[j])    d = min(d, slack[j]);
                }
                for (int j = 0; j < 26; ++j) {
                    if (sx[j]) lx[j] -= d;
                    if (sy[j]) ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        int ret = 0;
        for (int i = 0; i < 26; ++i) {
            ret += w[match[i]][i];    
        }
        printf("%.4f\n", 1.0*ret/N);
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) {
            for (int i = 0; i < 26; ++i) {
                v[i].clear();
            }
            scanf("%d %d %d", &N, &K, &M);
            char ch;
            for (int i = 1; i <= N; ++i) {
                cin >> ans[i];
                v[ans[i]-'A'].push_back(i); // 把为某一字符的位置统一保存起来
            }
            for (int i = 0; i < M; ++i) {
                for (int j = 1; j <= N; ++j) {
                    cin >> tmp[j];
                }
                build();
                KM();
            }
        }    
        return 0;    
    }
  • 相关阅读:
    洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…(树规)
    STREAMING #5 题解 3.高位网络
    冲刺NOIP2015提高组复赛模拟试题(五) 3.破坏基地
    冲刺NOIP2015提高组复赛模拟试题(五)2.道路修建
    冲刺NOIP2015提高组复赛模拟试题(五)1.数学作业
    洛谷P1186 玛丽卡 spfa+删边
    清北学堂 day6 花
    清北学堂 day6 兔子
    C++ STL 全排列函数
    flash分区的意义
  • 原文地址:https://www.cnblogs.com/Lyush/p/3026753.html
Copyright © 2011-2022 走看看