zoukankan      html  css  js  c++  java
  • ZOJ-2362 Beloved Sons 最大权值匹配

    题意:国王有N个儿子,现在每个儿子结婚都能够获得一定的喜悦值,王子编号为1-N,有N个女孩的编号同样为1-N,每个王子心中都有心仪的女孩,现在问如果安排,能够使得题中给定的式子和最大。

    分析:其实题目中那个开根号是个烟雾弹,只要关心喜悦值的平方即可。那么对王子和女孩之间构边,边权为喜悦值的平方,对于每一个王子虚拟出一个女孩边权为0,这样是为了所有的王子都能够有女孩可以配对,以便算法能够正确的执行。

    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    const int N = 405;
    const int inf = 0x3f3f3f3f;
    int n, m;
    int like[N];
    int w[N][N<<1];
    int match[N<<1];
    int lx[N], ly[N<<1], slack[N<<1];
    int vx[N], vy[N<<1];
    int marry[N];
    
    bool path(int u) {
        vx[u] = 1;
        for (int v = 1; v <= m; ++v) {
            if (vy[v] || w[u][v] == -1) continue;
            int t = lx[u]+ly[v]-w[u][v];
            if (!t) {
                vy[v] = 1;
                if (!match[v] || path(match[v])) {
                    match[v] = u;
                    return true;
                }
            } else {
                slack[v] = min(slack[v], t);
            }
        }
        return false;
    }
    
    void KM() {
        memset(lx, 0x80, sizeof (lx));
        memset(ly, 0, sizeof (ly));
        memset(match, 0, sizeof (match));
        memset(marry, 0, sizeof (marry));
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (w[i][j] != -1) {
                    lx[i] = max(lx[i], w[i][j]);
                }
            }
        }
        for (int i = 1; i <= n; ++i) {
            memset(slack, 0x3f, sizeof (slack));
            while (1) {
                memset(vx, 0, sizeof (vx));
                memset(vy, 0, sizeof (vy));
                if (path(i)) break;
                int d = inf;
                for (int j = 1; j <= m; ++j) {
                    if (!vy[j]) d = min(d, slack[j]);
                }
                if (d == inf) break;
                for (int j = 1; j <= n; ++j) {
                    if (vx[j]) lx[j] -= d;
                }
                for (int j = 1; j <= m; ++j) {
                    if (vy[j]) ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        for (int i = 1; i <= m; ++i) {
            if (match[i] && i <= n) {
                marry[match[i]] = i;
            }
        }
        for (int i = 1; i <= n; ++i) {
            printf(i == 1 ? "%d" : " %d", marry[i]);
        }
        puts("");
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) {
            memset(w, 0xff, sizeof (w));
            scanf("%d", &n);
            m = n << 1;
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &like[i]);
            }
            int x, y;
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &x);
                for (int j = 0; j < x; ++j) {
                    scanf("%d", &y);
                    w[i][y] = like[i] * like[i];
                }
                w[i][n+i] = 0;
            }
            KM();
        }
        return 0;
    }
  • 相关阅读:
    入坑C++之vs 新建C++项目
    入坑C++
    Solidity属性和方法的访问权限
    Solidity构造函数和析构函数
    网络直播应成为价值出口(人民时评)
    CODEVS 1203 判断浮点数是否相等
    CODEVS 1203 判断浮点数是否相等
    如何快速高效简洁的打开软件 干净利索的windows快捷程序启动器
    如何快速高效简洁的打开软件 干净利索的windows快捷程序启动器
    2018年开源状况:代码贡献超310亿行,而漏洞超16000个
  • 原文地址:https://www.cnblogs.com/Lyush/p/3204767.html
Copyright © 2011-2022 走看看