• 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;    
    }
  • 相关阅读:
    Linux应用程序的地址布局
    C/C++中的内存四区!
    编程语言的选择重不重要?对普通人而言,反其道而行更可靠!
    【C语言程序设计】C语言求最大公约数(详解版)!
    【C语言程序设计】C语言求最小公倍数(详解版)!
    【C语言程序设计】C语言求定积分!腻不腻害!
    你是因为什么而当程序员啊!网友们众说纷纭,从装b到被逼,理由层出不穷!
    华为程序员爆料:主动离职,公司竟也给n+1,到手15万,华为真良心!
    【C语言程序设计】C语言整数逆序输出程序!
    copy 和 mutablecopy
  • 原文地址:https://www.cnblogs.com/Lyush/p/3026753.html
Copyright © 2020-2023  润新知