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;
}

 

posted @ 2013-07-22 10:07  沐阳  阅读(421)  评论(0编辑  收藏  举报