• POJ2400 Supervisor, Supervisee 带权值匹配+枚举所有匹配情况


    题意:给定两个关系矩阵,分别表示雇主和雇员的相互好感度,好感度为1最优,N最差。如果一个人与好感度为P的人匹配的话,差值为P-1,现在要求是的总共的差值最小的匹配方法,并且输出所有的匹配方案。

    解法:将两两关系矩阵转化为边上的权值,然后进行一次最大匹配,最后dfs枚举输出结果,数据中给的矩阵上下颠倒了。

    代码如下:

    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    
    int N, sum, cnt;
    int mp1[20][20], mp2[20][20];
    int w[20][20];
    int lx[20], ly[20], sx[20], sy[20];
    int match[20], slack[20];
    
    void build() {
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                w[i][j] = -mp1[i][j]-mp2[i][j]; // 转化为最大匹配问题 
            }
        }
    }
    
    bool path(int u) {
        sx[u] = 1;
        for (int i = 1; i <= N; ++i) {
            if (sy[i]) continue;
            int t = lx[u]+ly[i]-w[u][i];
            if (!t) {
                sy[i] = 1;
                if (!match[i] || path(match[i])) {
                    match[i] = u;
                    return true;    
                }
            } else {
                slack[i] = min(slack[i], t);    
            }
        }
        return false;
    }
    
    void KM() {
        memset(match, 0, sizeof (match));
        memset(ly, 0, sizeof (ly));
        memset(lx, 0x80, sizeof (lx));
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                lx[i] = max(lx[i], w[i][j]);    
            }
        }
        for (int i = 1; i <= N; ++i) {
            memset(slack, 0x3f, sizeof (slack));
            while (1) {
                memset(sx, 0, sizeof (sx));
                memset(sy, 0, sizeof (sy));
                if (path(i)) break;
                int d = INF;
                for (int j = 1; j <= N; ++j) {
                    if (!sy[j])    d = min(d, slack[j]);
                }
                for (int j = 1; j <= N; ++j) {
                    if (sx[j]) lx[j] -= d;
                    if (sy[j]) ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
    }
    
    void dfs(int u, int tot, int deep) {
        if (tot < sum) return;
        if (deep == N) { // 匹配数量达到N 
            printf("Best Pairing %d\n", ++cnt);
            for (int i = 1; i <= N; ++i) {
                printf("Supervisor %d with Employee %d\n", i, match[i]);    
            }
            return;
        }
        for (int i = 1; i <= N; ++i) {
            if (!sy[i]) {
                sy[i] = 1;
                match[u] = i;
                dfs(u+1, tot+w[u][i], deep+1);
                sy[i] = 0;
            }
        }
    }
    
    void output(int ca) {
        double ret = 0;
        sum = cnt = 0;
        for (int i = 1; i <= N; ++i) {
            ret += w[match[i]][i];
            sum += w[match[i]][i];
        }
        ret = fabs(-ret / (2*N));
        printf("Data Set %d, Best average difference: %f\n", ca, ret);
        memset(sy, 0, sizeof (sy));
        dfs(1, 0, 0);
    }
    
    int main() {
        int T, x, ca = 0;
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &N);
            for (int i = 1; i <= N; ++i) {
                for (int j = 0; j < N; ++j) {
                    scanf("%d", &x);
                    mp1[x][i] = j; // 对第x个候选人的好感度排第j 
                }
            }
            for (int i = 1; i <= N; ++i) {
                for (int j = 0; j < N; ++j) {
                    scanf("%d", &x);
                    mp2[i][x] = j;
                }
            }
            build();
            KM();
            output(++ca);
            if (T) puts("");
        }
        return 0;    
    }
  • 相关阅读:
    VS注释提示英文变中文的方法
    Windows 10安裝.net Framework 3.5出現0X800F0954錯誤
    NodeJS+NPM+Bower+Android环境安装配置
    复合索引
    高并发的核心技术-幂等的实现方案
    Redis初使用
    数据库SQL查找包含某列的所有table
    多线程中的wait与sleep到底谁释放了锁
    https配置
    iOS下的实际网络连接状态检测(转)
  • 原文地址:https://www.cnblogs.com/Lyush/p/3013366.html
Copyright © 2020-2023  润新知